AsyncTask解析篇

流程解读
  • 自定义的继承类:因为AsyncTask为抽象类,无法直接创建,必须继承它实现一个子类。
a. 常见的方法
onPreExecute():在执行任务前调用,位于UI线程内
doInBackground():执行任务过程,位于非UI线程内
publishProgress():发布任务进度,一般在doInBackground()中调用,将数据传递给调onPregressUpdate()方法
onPregressUpdate():更新进度条,位于UI线程
onPostExecute():doInBackgound()方法完成后调用,位于UI线程
onCancelled():取消任务,位于UI线程
b. 定义类型
class MyTask extends AsyncTask
Params为传入的数据,比如url;因此,通常设置为String类型;
Progress为更新的进度,通常为Integer类型;
Result为返回的结果,如果我们希望返回一个文件,那么其对应类型为File;
  • 创建自定义的MyTask类
MyTask task = new MyTask(...);

创建该类,实际上就会调用AsyncTask的构造函数,如下:

//创建一个异步任务,注意这里必须在UI线程中创建
public AsyncTask(){
    //定义任务执行过程,注意这里还没开始执行任务,只是定义任务的执行过程
    mWorker = new WorkerRunnable() {
        @Override
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //交给子类去实现,获取到结果
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr){
                mCancelled.set(true);
                throw tr;
            } finally {
                //最后提交结果
                postResult(result);
            }
            return result;
        }
    };

    //实际上,这里用FutureTask包装Callable的目的是为之后提交给线程池执行,因为线程池并不接收Callable类型
    mFuture = new FutureTask(mWorker){
        @Override
        protected void done() {
            try {
                //若任务并没有执行过,则需要调用get()方法获取到结果,然后再提交结果
                postResultIfNotInvoked(get());
            } catch (InterruptedException e){
                android.util.Log.w(LOG_TAG, e);
            } catch (ExecutionException e){
                throw new RuntimeException("An error occurred while executing doInBackgound", e.getCause());
            } catch (CancellationException e){
                postResultIfNotInvoked(null);
            }
        }
    };
}

在AsyncTask构造函数内,初始化了两个mWorkermFuture两个变量。我们容易看到其中mFutrue实际上就是一个包装mWorker的FutrueTask实例。

private static abstract class WorkerRunnable implements Callable{
        Params[] mParams;
}

如上,实际上WorkerRunnable类型即为Callable类型。

  • 执行MyTask实例
mTask.execute(url);

其对应调用AsyncTask中的execute方法,如下:

//外部调用方法,执行任务
public final AsyncTask execute(Params... params){
    return executeOnExecutor(sDefaultExecutor, params);
}

//真正执行任务的地方
private AsyncTask 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 benn executed.");
        }
    }
    //标识为正在执行
    mStatus = Status.RUNNING;
    //执行前调用
    onPreExecute();
    mWorker.mParams = params;
    //执行任务!!!!
    exec.execute(mFuture);
    return this;
}

首先我们看到executeOnExecutor中的onPreExecute()方法,这是任务前执行的方法,然后执行exec.execute(mFuture),我们回到mFuture的定义,我们知道mFuture只是mWorker的一层包装,目的是为了交给线程池执行。而mWorkder中会执行result = doInBackground(mParams);,这个是交给子类去实现,获取到结果。最后再分发结果postResult(result);

//获取到Handler对象
private static Handler getHandler(){
    synchronized (AsyncTask.class){
        if (sHandler == null){
            sHandler = new InternalHandler();
        }
        return sHandler;
    }
}

//提交结果
private Result postResult(Result result){
    //创建消息
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult(this, result));
    //发送消息
    message.sendToTarget();
    return result;
}

我们可以看到消息将对应的结果通过一个InternalHandler类型来发送

//定义一个UI线程上的Handler对象
private static class InternalHandler extends Handler {
    public InternalHandler(){
        //获取到主线程
        super(Looper.getMainLooper());
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) {
        AsyncTaskResult result = (AsyncTaskResult) msg.obj;
        switch (msg.what){
            case MESSAGE_POST_RESULT:
                result.mTask.finish(result.mData[0]);
            break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

如上,该类型为UI线程上的一个Handler对象,保证发送的消息可以在UI线程中接收,我们先看到其MESSAGE_POST_RESULT类型,调用result.mTask.finish(result.mData[0]);方法

//任务执行完毕,提交结果,并标识
private void finish(Result result){
    if (isCancelled()){
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

我们可以看到在finish方法中,调用了onPostExecute(result)方法将结果发送出去。这样一个完整的流程就结束了。

当然,还有其更新进度方面,我们回到publishProgress()方法

//更新进度,并发送进度消息
protected final void publishProgress(Progress... values){
    if (!isCancelled()){
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult(this, values)).sendToTarget();
    }
}

回到InternalHandler中,我们可以看到其对应的消息类型,会调用onProgressUpdate()方法

细节解析
  • AsyncTask默认是使用串行执行的方式
//线程执行器,默认为串行执行
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

如何实现串行执行?
添加任务时,将下一个任务添加到上一个任务完成后执行

//实现串行执行
private static class SerialExecutor implements Executor{
    //双向队列,存储任务
    final ArrayDeque mTasks = new ArrayDeque<>();
    //当前正在执行的任务
    Runnable mActive;

    @Override
    public void execute(final Runnable r) {
        //添加到队尾
        //注意:a. 在这里不是直接传入r,而是重新定义一个runnable,目的在于当前任务执行完后,再从任务队列中获取到下一个,以保证串行
        //     b. 在这里只是重新定义runnable,并没有开始真正执行!!!
        mTasks.offer(new Runnable() {
            @Override
            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);
        }
    }
}
  • 定义线程池的方法

亮点在于:静态化构造线程池,这样当构建对象时,会初始化线程池

//获取当前CPU核心数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//定义线程池核心容量
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT-1, 4));
//定义线程池最大容量
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//过剩的空闲线程的存活时间
private static final int KEEP_ALIVE_SECONDS = 30;

//自定义工厂方法,标记线程,以便管理
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
    private final AtomicInteger mCount = new AtomicInteger(1);

    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
    }
};
//任务队列
private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue<>(128);
//线程池
public static final Executor THREAD_POOL_EXECUTOR;

//构造一个线程池
static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            sPoolWorkQueue, sThreadFactory);
    threadPoolExecutor.allowCoreThreadTimeOut(true);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
  • 关于不定参数的使用
private static class AsyncTaskResult{
    final AsyncTask mTask;
    final Data[] mData;

    public AsyncTaskResult(AsyncTask mTask, Data... mData) {
        this.mTask = mTask;
        this.mData = mData;
    }
}
使用不定参数的目的在于在构造这样的类时,传入的Data数据类型可变:
private Result postResult(Result result){
    //创建消息
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult(this, result));
}

protected final void publishProgress(Progress... values){
    if (!isCancelled()){
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult(this, values)).sendToTarget();
    }
}
如上,我们可以看到构造AsyncTaskResult对象时,既可以传入单个对象,也可以传入数组对象。

你可能感兴趣的:(AsyncTask解析篇)