AsyncTask原理分析

单个网络请求更新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

  1. 首先在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);
                    }
                }
            };
        }
  2. 声明完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方法

  3. 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);
                }
            }
        }
  4. 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之后的版本中不会出现,因为线程是一个接一个执行的,不会出现超过任务数而执行饱和策略的情况。

猜你喜欢

转载自blog.csdn.net/S_Alics/article/details/101455095