AsyncTask源码分析

AsyncTask简介

  • AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。

  • AsyncTask实际上就是封装了Thread和Handler,可以让我们在后台进行计算并且把计算的结果及时更新到UI上,而这些正是Thread+Handler所做的事情,AsyncTask的作用就是简化Thread+Handler

  • 在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务

AsyncTask步骤

一个异步任务的执行一般包括以下几个步骤:

1.execute(Params… params):

执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。

2.onPreExecute():

在execute(Params…params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。在主线程中执行。

3.doInBackground(Params…params):

在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress…values)来更新进度信息。在线程池中执行。

4.onProgressUpdate(Progress…values):

在调用publishProgress(Progress…values)时,此方法被执行,直接将进度信息更新到UI组件上。 在主线程中执行。

5.onPostExecute(Result result):

当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。在主线程中执行。

注意事项

1.异步任务的实例必须在UI线程中创建。
2.AsyncTask的类必须在UI线程加载(从4.1开始系统会帮我们自动完成)
3.execute(Params… params)方法必须在UI线程中调用。
4.不要在你的程序中去直接调用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
5.不能在doInBackground(Params… params)中更改UI组件的信息。
6.一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
7.AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask
8.在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务

AsyncTask工作原理

AsyncTask启动首先会调用execute,先从execute方法开始分析,execute又会调用executeOnExecutor,它们的实现如下:

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

sDefaultExecutor实现了一个串行的线程池,一个进程中所有的AsyncTask都会在这个线程池中排队。onPreExecute会先执行。然后通过exec.execute(mFuture)执行这个线程池。

/** 
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread. 
     */  
    public AsyncTask() {  
        mWorker = new WorkerRunnable<Params, Result>() {  
            public Result call() throws Exception {  
                mTaskInvoked.set(true);  

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
                //noinspection unchecked  
                return postResult(doInBackground(mParams));  
            }  
        };  

        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 occured while executing doInBackground()",  
                            e.getCause());  
                } catch (CancellationException e) {  
                    postResultIfNotInvoked(null);  
                }  
            }  
        };  
    }  

首先系统会把AsyncTask的mParams参数封装为FutureTask对象,FutureTask是一个并发类。接着这个FutureTask会交给SerialExecutor的execute方法去处理,execute首先会把FutureTask插入任务队列mTasks,详细实现如下:

/*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的 
 *目前我们需要知道,asyncTask.execute(Params ...)实际上会调用 
 *SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候, 
 *首先你的task会被加入到任务队列,然后排队,一个个执行 
 */  
private static class SerialExecutor implements Executor {  
    //线性双向队列,用来存储所有的AsyncTask任务  
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();  
    //当前正在执行的AsyncTask任务  
    Runnable mActive;  

    public synchronized void execute(final Runnable r) {  
        //将新的AsyncTask任务加入到双向队列中  
        mTasks.offer(new Runnable() {  
            public void run() {  
                try {  
                    //执行AsyncTask任务  
                    r.run();  
                } finally {  
                    //当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话  
                    //这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务  
                    scheduleNext();  
                }  
            }  
        });  
        //如果当前没有任务在执行,直接进入执行逻辑  
        if (mActive == null) {  
            scheduleNext();  
        }  
    }  

    protected synchronized void scheduleNext() {  
        //从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行  
        if ((mActive = mTasks.poll()) != null) {  
            THREAD_POOL_EXECUTOR.execute(mActive);  
        }  
    }  
}  

SerialExecutor实现了AsyncTask的排队过程。ArrayDeque 类提供了可调整大小的阵列,并实现了Deque接口。从任务队列中取出队列头部的任务,如果有就交给并发线程池HREAD_POOL_EXECUTOR去执行。

THREAD_POOL_EXECUTOR线程池用于真正执行任务。

//获取当前的cpu核心数  
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();  
//线程池核心容量  
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;  
//线程池最大容量  
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;  
//过剩的空闲线程的存活时间  
private static final int KEEP_ALIVE = 1;  
//ThreadFactory 线程工厂,通过工厂方法newThread来获取新线程  
private static final ThreadFactory sThreadFactory = new ThreadFactory() {  
    //原子整数,可以在超高并发下正常工作  
    private final AtomicInteger mCount = new AtomicInteger(1);  

    public Thread newThread(Runnable r) {  
        return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());  
    }  
};  
//静态阻塞式队列,用来存放待执行的任务,初始容量:128个  
private static final BlockingQueue<Runnable> sPoolWorkQueue =  
        new LinkedBlockingQueue<Runnable>(128);  

/** 
 * 静态并发线程池,可以用来并行执行任务,尽管从3.0开始,AsyncTask默认是串行执行任务 
 * 但是我们仍然能构造出并行的AsyncTask 
 */  
public static final Executor THREAD_POOL_EXECUTOR  
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  

WorkerRunnable的call()方法最终会在线程池中执行,如下

    mWorker = new WorkerRunnable<Params, Result>() {  
            public Result call() throws Exception {  
                mTaskInvoked.set(true);  

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
                //noinspection unchecked  
                return postResult(doInBackground(mParams));  
            }  
        };            

mTaskInvoked.set(true),表示当前任务已经被调用,然后执行doInBackground方法,接着返回值传递给postResult()方法,如下:

//doInBackground执行完毕,发送消息  
    private Result postResult(Result result) {  
        @SuppressWarnings("unchecked")  
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,  
                new AsyncTaskResult<Result>(this, result));  
        message.sendToTarget();  
        return result;  
    }  

postResult会通过sHandler发送一个MESSAGE_POST_RESULT的消息。sHandler实现如下:

//AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息  
    private static class InternalHandler extends Handler {  
        @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;  
            }  
        }  
    }  

sHandler收到MESSAGE_POST_RESULT后会调用finish方法,如果被取消任务,就调用onCancelled,否则调用onPostExecute:

//任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用  
    private void finish(Result result) {  
        if (isCancelled()) {  
            onCancelled(result);  
        } else {  
            onPostExecute(result);  
        }  
        mStatus = Status.FINISHED;  
    }

解决3.0以上版本不能并行执行的问题

直接调用executeOnExecutor:
new MyAsyncTask(“AsyncTask#1”).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,”“);

发布了46 篇原创文章 · 获赞 23 · 访问量 7万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章