单个网络请求更新UI用Handler比较方便,但多个网络请求处理最好使用AsyncTask。
核心方法
- onPreExecute():在主线程中执行。一般在任务执行前做准备工作,比如对 UI 做一些标记。
- doInBackground(Params...params):在线程池中执行。在 onPreExecute方法执行后运行,用来执行较为耗时的操作。在执行过程中可以调用publishProgress(Progress...values)来更新进度信息。
- onProgressUpdate(Progress...values):在主线程中执行。当调用 publishProgress(Progress...values)时,此方法会将进度更新到UI组件上。
- onPostExecute(Result result):在主线程中执行。当后台任务执行完成后,它会被执行。doInBackground方法得到的结果就是返回的result的值。此方法一般做任务执行后的收尾工作,比如更新UI和数据。
核心成员
- WorkerRunnable:AsyncTask在构造方法中初始化的类,实现了Callable接口并实现了其call方法。call方法内部调用了doInBackground方法来处理任务并得到结果,并最终调用postResult将结果投递出去
- FutureTask:这是一个可管理的异步任务,它实现了Runnable和Futrue这两个接口。因此,它可以包装 Runnable和Callable,并提供给Executor执行。在这里WorkerRunnable作为参数传递给了FutureTask,用来监视目标线程调用call()方法的情况,例如用 Future的get()方法以获取结果时,当前线程就会阻塞,直到call()方法返回结果
- THREAD_POOL_EXECUTOR:执行具体网络请求的线程池,其核心线程和线程池允许创建的最大线程数都是由CPU的核数来计算出来的。它采用的阻塞队列是LinkedBlockingQueue,容量为128。
- SerialExecutor :管理请求任务的线程池,内部维护了一个根据元素数量调节容量的双向队列ArrayDeque,作用是ArrayDeque负责存储请求,并串行执行请求任务
- Handler:负责将结果数据传递给UI线程以便更新UI
大致流程原理=两个线程池+Handler
- 首先在AsyncTask的构造函数里初始化了一个WorkerRunnable,它实现了Callable接口并实现了其call方法。call方法内部调用了doInBackground方法来处理任务并得到结果,并最终调用postResult将结果投递出去;另外还初始化了一个FutureTask,它是worker的包装类,用来监视目标线程调用call()方法的情况,例如用 Future的get()方法以获取结果时,当前线程就会阻塞,直到call()方法返回结果。
public AsyncTask(@Nullable Looper callbackLooper) { mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper); mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Result result = null; try { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked result = doInBackground(mParams); Binder.flushPendingCommands(); } catch (Throwable tr) { mCancelled.set(true); throw tr; } finally { postResult(result); } return result; } }; mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { postResultIfNotInvoked(get()); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occurred while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } } }; }
- 声明完AsyncTask的实例后,在理想情况下,就可以调用execute()方法来执行请求任务了。
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } @MainThread 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(); //将参数赋值到上一步初始化的WorkerRunnable里 mWorker.mParams = params; //此exec是SerialExecutor exec.execute(mFuture); return this; }
可以看到AsyncTask的execute方法最后执行的是exec.execute(mFuture)方法,也就是SerialExecutor的execure方法
-
SerialExecutor是一个串行的线程池,当调用SerialExecutor的execute方法时,会将FutureTask加入到mTasks中。当任务执行完或者当前没有活动的任务时都会执行scheduleNext方法,它会从mTasks取出FutureTask任务并交由 THREAD_POOL_EXECUTOR 处理。
private static class SerialExecutor implements Executor { //双向队列存储请求任务 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); Runnable mActive; //synchronized保证请求的串行执行,这里区别于Android3.0之前的版本,之前是并行,会有问题 public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { //队列的offer方法将请求添加到队列中 public void run() { try { //这里执行的是FutureTask的run方法,最终执行WorkerRunnable的call方法 r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } }
- WorkerRunnable的call方法内部调用了doInBackground方法来处理任务并得到结果,并调用postResult将结果投递出去
private Result postResult(Result result) { @SuppressWarnings("unchecked") Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; } private static class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); } @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override 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; } } } private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { //更新UI onPostExecute(result); } mStatus = Status.FINISHED; }
Android 3.0前后 AsyncTask的区别
- 3.0版本之前的AsyncTask是并行处理任务,所以缺点就是线程池最大的线程数为128,加上阻塞队列的10个任务,AsyncTask最多能同时容纳138个任务,当提交第139个任务时就会执行饱和策略,默认抛出RejectedExecutionException(拒绝执行)异常。
- 3.0及以上版本用SerialExecutor作为默认的线程,它将任务串行处理,保证一个时间段只有一个任务执行,因此Android 3.0之前版本的缺点在Android 3.0之后的版本中不会出现,因为线程是一个接一个执行的,不会出现超过任务数而执行饱和策略的情况。