Android中AsyncTask分析--你所不注意的坑
AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
本文不分析AsyncTask的使用,它的使用教程网上一搜一大堆,本文主要分析它的内部逻辑和实现,它是怎么实现异步的,它是怎么处理多个任务的,是并发么??
一、线程任务的调度
在AsyncTask内部会创建一个类相关的线程池来管理要运行的任务,也就就是说当你调用了AsyncTask的execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Therad。
在Android4.0版本中它内部是有两个线程池:SerialExecutor和ThreadPoolExecutor,SerialExecutor是串行的,ThreadPoolExecutor是并发的,而默认的就是SerialExecutor的,所以你一个程序中如果用了好几个AsyncTask你就得注意了:不要忘了换成并发的线程池执行。下面演示一下,穿行的调度
public class AsyncTaskDemoActivity extends Activity { private static int ID = 0; private static final int TASK_COUNT = 9; private static ExecutorService SINGLE_TASK_EXECUTOR; private static ExecutorService LIMITED_TASK_EXECUTOR; private static ExecutorService FULL_TASK_EXECUTOR; static { SINGLE_TASK_EXECUTOR = (ExecutorService) Executors.newSingleThreadExecutor(); LIMITED_TASK_EXECUTOR = (ExecutorService) Executors.newFixedThreadPool(7); FULL_TASK_EXECUTOR = (ExecutorService) Executors.newCachedThreadPool(); }; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.asynctask_demo_activity); String title = "AsyncTask of API " + VERSION.SDK_INT; setTitle(title); final ListView taskList = (ListView) findViewById(R.id.task_list); taskList.setAdapter(new AsyncTaskAdapter(getApplication(), TASK_COUNT)); } private class AsyncTaskAdapter extends BaseAdapter { private Context mContext; private LayoutInflater mFactory; private int mTaskCount; List<SimpleAsyncTask> mTaskList; public AsyncTaskAdapter(Context context, int taskCount) { mContext = context; mFactory = LayoutInflater.from(mContext); mTaskCount = taskCount; mTaskList = new ArrayList<SimpleAsyncTask>(taskCount); } @Override public int getCount() { return mTaskCount; } @Override public Object getItem(int position) { return mTaskList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mFactory.inflate(R.layout.asynctask_demo_item, null); SimpleAsyncTask task = new SimpleAsyncTask((TaskItem) convertView); /* * It only supports five tasks at most. More tasks will be scheduled only after * first five finish. In all, the pool size of AsyncTask is 5, at any time it only * has 5 threads running. */ task.execute(); // use AsyncTask#SERIAL_EXECUTOR is the same to #execute(); // task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); // use AsyncTask#THREAD_POOL_EXECUTOR is the same to older version #execute() (less than API 11) // but different from newer version of #execute() // task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); // one by one, same to newer version of #execute() // task.executeOnExecutor(SINGLE_TASK_EXECUTOR); // execute tasks at some limit which can be customized // task.executeOnExecutor(LIMITED_TASK_EXECUTOR); // no limit to thread pool size, all tasks run simultaneously //task.executeOnExecutor(FULL_TASK_EXECUTOR); mTaskList.add(task); } return convertView; } } private class SimpleAsyncTask extends AsyncTask<Void, Integer, Void> { private TaskItem mTaskItem; private String mName; public SimpleAsyncTask(TaskItem item) { mTaskItem = item; mName = "Task #" + String.valueOf(++ID); } @Override protected Void doInBackground(Void... params) { int prog = 1; while (prog < 101) { SystemClock.sleep(100); publishProgress(prog); prog++; } return null; } @Override protected void onPostExecute(Void result) { } @Override protected void onPreExecute() { mTaskItem.setTitle(mName); } @Override protected void onProgressUpdate(Integer... values) { mTaskItem.setProgress(values[0]); } } } class TaskItem extends LinearLayout { private TextView mTitle; private ProgressBar mProgress; public TaskItem(Context context, AttributeSet attrs) { super(context, attrs); } public TaskItem(Context context) { super(context); } public void setTitle(String title) { if (mTitle == null) { mTitle = (TextView) findViewById(R.id.task_name); } mTitle.setText(title); } public void setProgress(int prog) { if (mProgress == null) { mProgress = (ProgressBar) findViewById(R.id.task_progress); } mProgress.setProgress(prog); } }
2.你想要的并发执行
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
当然也可以换成你自己的线程池。
二、源码分析
1.成员变量:
定义了需要用到的成员,可以根据名字就能知道干什么的
//生产线程的工厂 private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); } }; //存放任务的阻塞队列 private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(10); /** * 可以平行的执行任务!就是并发的 * An {@link Executor} that can be used to execute tasks in parallel. */ public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); /** * 线性执行的执行器 * An {@link Executor} that executes tasks one at a time in serial * order. This serialization is global to a particular process. */ public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); //内部交互的handler private static final InternalHandler sHandler = new InternalHandler(); //默认的Executor private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
定义了需要用到的成员,可以根据名字就能知道干什么的,另外注意都是static修饰的:
第二行的sThreadFactory是创建线程的;
第十行的sPoolWorkQueue阻塞队列,存放任务的;
第十七行是 THREAD_POOL_EXECUTOR是线程池,这个是并发执行的线程池;
第26行是线性调度的线程池,SERIAL_EXECUTOR,执行完一个才会执行下一个;
第28行是一个内部封装的Handler:InternalHandler
第30行可以看出他默认的是线性调度的线程池, Executor sDefaultExecutor = SERIAL_EXECUTOR,看到这里你应该注意一个问题,如果程序里有好多个AsyncTask,它们就是线性调度的,这肯定可你预想的不一样,所以你别忘了换成并发的执行器。
2.内部Handler的使用:
2.1 自定义的InternalHandler(内部handler)
private static class InternalHandler extends Handler { @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override //接受message的处理,可以看到根据状态选择是完成了,还是更新着 public void handleMessage(Message msg) { AsyncTaskResult result = (AsyncTaskResult) msg.obj; switch (msg.what) { case MESSAGE_POST_RESULT: // There is only one result result.mTask.finish(result.mData[0]); break; case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break; } } }
在上边handleMessage中,根据msg进行判断,是完成了还是在更新;
任务完成调用finish方法,在其中执行你定义的onPostExecute方法,
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
3.构造方法
public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return postResult(doInBackground(mParams)); } }; mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { final Result result = get(); postResultIfNotInvoked(result); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } catch (Throwable t) { throw new RuntimeException("An error occured while executing " + "doInBackground()", t); } } }; }
构造方法中其实隐藏的信息很多,WorkerRunnable和FutureTask;
其中WorkerRunnable继承了Callable接口,应该是用于在未来某个线程的回调接口,在其中执行了postResult(doInBackground(mParams));调用doInBackground,并用postResult方法把result发送到主线程。
FutureTask你看类的介绍是说控制任务的,控制任务的开始、取消等等,在这不细究,跟本文关系不大,而且我也没看明白。
第17行有一个方法:postResultIfNotInvoked(result);根据名字可以看出来是如果没有调用就把结果post出去,所以他应该是处理取消的任务的。
看下postResult方法:代码很少也很简单,就是把msg发送给handler:
//用shandler把设置message,并发送。 private Result postResult(Result result) { Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; }
构造方法就分析到这,下一步就是execute():
3.1 按照执行过程流程,实例化完,就可以调用execute():
//Params... 就相当于一个数组,是传给doInBackground的参数 public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } //执行逻辑 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: throw new IllegalStateException("Cannot execute task:" + " the task is already running."); case FINISHED: throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)"); } } //改变状态 mStatus = Status.RUNNING; //准备工作 onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; }
代码逻辑很清晰,没有几行:
20行:修改了状态;
21行:准备工作;
24行:设置参数;
25行:线程池调用执行,注意参数是mFuture。
3.2 execute的执行逻辑
就以它定义SerialExecutor为例:
/*An {@link Executor} that executes tasks one at a time in serial * order. This serialization is global to a particular process.*/ private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }
可以看到它的方法都是用synchronized关键字修饰的,且在他的介绍里也说了在同一时间只有一个任务在执行。
- 在execute方法中把Future 的 run方法封装到Runnable里,放到Task队列中,如果mActive为空则调用scheduleNext方法执行任务;在这里还有一个细节就是执行完r.run(),还有个finally模块调用scheduleNext 方法,所以它才会一个接一个的执行任务。
- 而在scheduleNext 中使用THREAD_POOL_EXECUTOR 执行任务。
三、AsyncTask中异步的处理逻辑
没有忘了前边构造方法中的postResult(doInBackground(mParams))和postResultIfNotInvoked(result);方法吧,如果忘了翻前边去看。这两个方法把执行成功的和失败的任务都包含了。
所以我们可以设想一下它是怎么执行的:
1.在executeOnExecutor方法中给变量赋值
2.用执行器Executor另起线程执行任务
3.在Executor中一些复杂的逻辑,用FutureTask进行判断任务是否被取消,如果没有就调用回调接口call()方法,
4.在call()方法中调用了postResult(doInBackground(mParams));
5.postResult发送给主线程的Handler进行后续处理。
看的时候可以画下图,会很清晰,基本逻辑就这样,好AsyncTask就分析到这,欢迎纠错。。。
转发请注明出处,原文地址:http://www.cnblogs.com/jycboy/p/asynctask_1.html