线程通信之AsyncTask源码分析

AsyncTask的原型如下:

package android.os;

public abstract class AsyncTask<Params, Progress, Result> {
	...
}

可见,AsyncTask是抽象类,必须实现它的子类才能使用,下面都是可重写的方法:

    @WorkerThread
    protected abstract Result doInBackground(Params... params);

    @MainThread
    protected void onPreExecute() {
    }

    @MainThread
    protected void onPostExecute(Result result) {
    }

    @MainThread
    protected void onProgressUpdate(Progress... values) {
    }

    @MainThread
    protected void onCancelled(Result result) {
        onCancelled();
    }

    @MainThread
    protected void onCancelled() {
    }

可见,只有doInBackground方法是必须在子类实现的。由于AsyncTask一般用在执行后台任务然后更新UI,所以通常至少会重写onPostExecute方法。当我们在doInBackground方法中定义好后台任务后,就可以通过execute方法传入参数:

    @MainThread
    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();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

executeOnExecutor中,会先回调onPreExecute()做一些准备工作,这是AsyncTask运行的第一步。然后,后台任务会在exec.execute(mFuture)中执行,我们先来了解一下这个Executor exec参数:

package java.util.concurrent;

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     */
    void execute(Runnable command);
}

Executor只是一个接口,它用于决定Runnable怎么执行,线程池类ThreadPoolExecutor就实现了该接口。在AsyncTask中,Runnable默认交给sDefaultExecutor去执行:

    /**
     * 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();

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    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);
            }
        }
    }

sDefaultExecutor被赋值为一个串行执行者,这个执行者会将传进来的Runnable串行执行,就是上一个Runnable执行完了才执行下一个。这个Runnable会继续交给线程池THREAD_POOL_EXECUTOR去执行:

    private static final int CORE_POOL_SIZE = 1;
    private static final int MAXIMUM_POOL_SIZE = 20;
    private static final int KEEP_ALIVE_SECONDS = 3;

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(), sThreadFactory);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

了解完Executor,我们再来看看FutureTask<Result> mFuture,既然它能交给Executor去执行,显然它是实现了Runnable接口的。只不过,它是实现了RunnableFuture接口,而RunnableFuture接口继承于Runnable接口:

package java.util.concurrent;

public class FutureTask<V> implements RunnableFuture<V> {

    public void run() {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
        ...
    }
}

FutureTask里的run方法,会调用Callablecall方法。Callable是一个接口,与Runnable接口有点类似,不过它的call方法有返回值,也可以抛出异常:

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     */
    V call() throws Exception;
}

FutureTaskcallable属性可以在构造函数中传入。在AsyncTask的构造函数中可见,传给FutureTask mFutureCallable是一个WorkerRunnable对象。WorkerRunnableAsyncTask的内部抽象类,它只是在Callable的基础上添加了一组属性。

    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
        Params[] mParams;
    }

现在来看AsyncTask的构造函数,在初始化过程中,会新建一个WorkerRunnable对象,在传给FutureTask

    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);
                }
            }
        };
    }

WorkerRunnablecall方法中,可以看到会执行doInBackground方法,到这里就是是AsyncTask运行的第二步了。
如果要在后台任务运行过程中,在前台显示进度,则需要在doInBackground方法里显式调用publishProgress方法来向UI线程告诉进度:

    @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }

    private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

由于publishProgress方法是在后台调用的,所以进度值需要通过Handler发送给UI线程:

    private final Handler mHandler;

    private Handler getHandler() {
        return mHandler;
    }

mHandler也是在AsyncTask的构造函数中初始化的,默认情况下,它会绑定到主线程:

    private static Handler getMainHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler(Looper.getMainLooper());
            }
            return sHandler;
        }
    }

    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;
            }
        }
    }

mHandler接收到MESSAGE_POST_PROGRESS消息时,就会回调AsyncTaskonProgressUpdate方法,这是AsncTask运行的第三步
WorkerRunnablecall方法中,执行完doInBackground方法,会调用postResult方法,该方法与publishProgress方法类似,都是在后台往主线程发送消息:

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

mHandler接收到MESSAGE_POST_RESULT消息时,就会回调AsyncTaskfinish方法:

    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

这里分两种情况,如果后台任务被取消了,会回调onCancelled方法,否则按正常情况回调onPostExecute方法。这是AsncTask运行的第四步。到这里,后台任务也就完成了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值