0
点赞
收藏
分享

微信扫一扫

AsyncTask 源码解析

AsyncTask 基本使用

  • Params

在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。

  • Progress

后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。

  • Result

当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。

因此,一个最简单的自定义AsyncTask就可以写成如下方式:

class DownloadTask extends AsyncTask<Void, Integer, Boolean> {

……

}

这里我们把AsyncTask的第一个泛型参数指定为Void,表示在执行AsyncTask的时候不需要传入参数给后台任务。第二个泛型参数指定为Integer,表示使用整型数据来作为进度显示单位。第三个泛型参数指定为Boolean,则表示使用布尔型数据来反馈执行结果。 当然,目前我们自定义的DownloadTask还是一个空任务,并不能进行任何实际的操作,我们还需要去重写AsyncTask中的几个方法才能完成对任务的定制。

经常需要去重写的方法有以下四个:

onPreExecute()

这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。

doInBackground(Params...)

这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果进行返回,如果AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress...)方法来完成。

onProgressUpdate(Progress...)

当在后台任务中调用了publishProgress(Progress...)方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。 onPostExecute(Result)

当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。

AsyncTask 源码分析

AsyncTask 前世今生

在android1.6以前,它是串行执行,android1.6开始采用线程池处理并行任务,从android3.0开始,采用串行执行任务,仍然可以调用executeOnExecute方法并行执行任务。Android 3.0之前,AsyncTask核心线程数为5个,最大核心线程数为128个,加上阻塞队列任务10个共容纳138个任务,当提交的任务超过138个时就会执行饱和策略,抛出异常。

AsyncTask 线程池配置的参数

核心线程数等于CPU核心数+1

最大线程数为CPU核心数2倍+1

核心线程无超时时长,非核心线程超时时长为1秒

任务队列容量128

AsyncTask 线程池分析

AsyncTask内部有两个线程池(SerialExecutor与THREAD_POOL_EXECUTOR)和一个IntentHandler, SerialExecutor用于任务排队,

THREAD_POOL_EXECUTOR用于真正执行任务,IntentHandler用于将执行环境从线程池中切换到主线程。

创建AsynacTask并初始化必须在主线程中执行

/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. */
public AsyncTask() {   
this((Looper) null);}/** * Creates a new asynchronous task. This constructor must be invoked on the UI thread. * * @hide */
public AsyncTask(@Nullable Handler handler) {   
this(handler != null ? handler.getLooper() : null);
}

创建一个异步任务AsyncTask

public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()

getMainHandler方法并初始化InternalHandler? 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);
        }
    }
};

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

sHandler是一个静态变量,将执行环境切换到主线程,这就要求sHandler在主线程中创建,静态成员变量会在加载类时进行初始化变相要求AsyncTask在主线程中加载

private static InternalHandler sHandler; private void postResultIfNotInvoked(Result result) { final boolean wasTaskInvoked = mTaskInvoked.get(); if (!wasTaskInvoked) { postResult(result); } }

private Result postResult(Result result) { @SuppressWarnings(&quot;unchecked&quot;) //发送消息切换到主线程中执行 Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult&lt;Result&gt;(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

//执行finish方法 result.mTask.finish(result.mData[0]); break; case MESSAGE_POST_PROGRESS: //执行onProgressUpdate方法 result.mTask.onProgressUpdate(result.mData); break; } } } private void finish(Result result) { //如果当前任务取消了,就调用onCancelled,否则调用onPostExecute方法 if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; } //doBackground方法调用publishProgress方法从子线程切换到主线程进行UI更新 @WorkerThread protected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult&lt;Progress&gt;(this, values)).sendToTarget(); } }

SerialExecutor源码分析

private static class SerialExecutor implements Executor { final ArrayDeque&lt;Runnable&gt; mTasks = new ArrayDeque&lt;Runnable&gt;(); 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);
    }
}

}

SerialExecutor 总结

SerialExecutor使用ArrayQueue来管理Runnable对象,当一次性启动很多任务时,首先第一次运行executor方法,会调用ArrayQueue将任务添加到队列尾部,并判断mActive是否为空,为空调用scheduleNext方法,这个方法会从队列头部取值,然后赋值给mActive,然后调有THREAD_POOP_EXECUTOR取出并执行runnable对象。之后又有新任务,将会调用offer将runnable传入队列尾部,此时mActivie不为空,就不调用scheduleNext方法。

每当任务执行完毕后才会执行下一个任务,SerialExecutor模仿的是单一线程池操作,同一时刻只会有一个任务执行。

举报

相关推荐

0 条评论