记得14那年导师的第一个项目让我有机会了解 Android,那时可以说是需要什么功能就去找相应的资料。针对网络请求这一模块,在 Android 4.0 之后的版本如果在主线程执行网络请求,运行时是会报错的(我当时就遭过)。因为主线程主要是负责更新界面并与用户进行交互,不能执行耗时的操作。针对这个问题,我通过百度找到的解决方案大体就是创建一个线程 Thread,在线程的 run() 方法中去执行网络请求,最后再通过 Handler 发送消息通知 UI 线程来刷新界面。

同年的暑假,我有机会去一家公司实习(公司氛围和同事都很nice)。在实习过程中慢慢的接触了今天的主角 – AsyncTask。那时可没想太多,拿过来就用啊。可能自己的无知,像 AsyncHttpClient 这么鼎鼎有名的网络请求开源库在那时我居然不知道。现在回想起来,无知者,罪过、罪过。

一、初识 AsyncTask

不过今天不是来讨论 AsyncHttpClinet 的,毕竟今天的主角可是 AsyncTask。先看看我们一般使用 AsyncTask 的操作流程:代码块1

public class MyAsyncTask extends AsyncTask<Params, Progress, Result> {    @Override    protected void onPreExecute() {        super.onPreExecute();    }    @Override    protected Result doInBackground(Params... params) {        // do something        ...        return null;    }    @Override    protected void onPostExecute(Result result) {        super.onPostExecute(s);    }}new MyAsyncTask().execute(...);

首先我们先是定义一个类 MyAsyncTask 并让其继承 AsyncTask。由于 doInBackground() 方法是抽象的,所以必须重写。当然,我们也会根据需求去重写其他方法,如 onPreExecute()、onPostExecute()、onPreogressUpdate()等。

  1. onPreExecute(): 在这个方法里一般是进行一些初始化的工作;
  2. doInbackground(): 我们会在这个方法里执行如网络请求等操作,同时根据需要将结果返回;
  3. onProgressUpdate(): 显示任务执行的进度。不过我们要在 doInBackground() 方法手动调用 publishProgress() 方法后这个方法才能得到响应。
  4. onPostExecute(): 这个方法接收任务执行后返回的结果。

二、AsyncTask 的核心源头

好了,万事俱备,只欠执行啦 new MyAsyncTask().execute()。来看看 execute() 方法具体是做了那些事:代码块2

#AsyncTask.java@MainThreadpublic final AsyncTask execute(Params... params) {    return executeOnExecutor(sDefaultExecutor, params);}@MainThreadpublic final AsyncTask executeOnExecutor(Executor exec,            Params... params) {    // mStatus 属性看下面定义            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;}private volatile Status mStatus = Status.PENDING;public enum Status {    /**     * Indicates that the task has not been executed yet.     */    PENDING,    /**     * Indicates that the task is running.     */    RUNNING,    /**     * Indicates that {@link AsyncTask#onPostExecute} has finished.     */    FINISHED,}

可以看到,execute() 方法会跳转到 executeOnExecutor()。补充一下:Status 是一个枚举类,而 mStatus 的默认初始值为 Status.PENDING,表示当前任务是处于待办状态。首先先是对 mStatus 进行判断,如果当前任务不是处于 Status.PENDING,则会报异常。这也是为什么我们不能执行多次 execute() 的原因。

顺利的情况下,mStatus 会被置成运行状态 Status.RUNNING;接着调用 onPreExecute(),我们可以在该方法里进行一些初始化操作。然后就是将我们传递进来的参数存放在 mWorker.mParams 里,看看 mWoeker 是什么玩意吧:代码块3

#AsyncTask.javaprivate final WorkerRunnable mWorker;private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {    Params[] mParams;}public AsyncTask() {    mWorker = new WorkerRunnable() {        public Result call() throws Exception {            mTaskInvoked.set(true);            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);            //noinspection unchecked            Result result = doInBackground(mParams);            Binder.flushPendingCommands();            return postResult(result);        }    };    mFuture = new FutureTask(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);            }        }    };}

原来在 AsyncTask 的构造方法中创建了两个对象:mWorker 和 mFuture。源码写得很清楚,mWorker 是一个 WorkerRunnable

#AsyncTask.javaprivate static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;public static final Executor SERIAL_EXECUTOR = new SerialExecutor();private static class SerialExecutor implements Executor {    final ArrayDeque mTasks = new ArrayDeque();    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);        }    }}public static final Executor THREAD_POOL_EXECUTOR            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

我们先理一理吧。在执行 execute() 方法后,最終会调用 sDefaultExecutor.execute()。在这方法里,首先会将我们传递进来的 mFuture 封装到一个 Runnable 对象中,同时再将这个 Runnable 对象将添加到任务队列 mTasks 中。然后判断 mActive 为空时则执行 scheduleNext()。这个方法做的事就是从队列中取出消息,然后交给 THREAD_POOL_EXECUTOR 去执行。而 THREAD_POOL_EXECUTOR 是一个线程池执行器 ThreadPoolExecutor。让我们一起跳转到其 execute() 方法里:

public void execute(Runnable command) {    if (command == null)        throw new NullPointerException();    int c = ctl.get();    if (workerCountOf(c) < corePoolSize) {        if (addWorker(command, true))            return;        c = ctl.get();    }    if (isRunning(c) && workQueue.offer(command)) {        int recheck = ctl.get();        if (! isRunning(recheck) && remove(command))            reject(command);        else if (workerCountOf(recheck) == 0)            addWorker(null, false);    }    else if (!addWorker(command, false))        reject(command);}

这里最主要的还是addWorker() 操作:

private boolean addWorker(Runnable firstTask, boolean core) {    retry:    for (;;) {        int c = ctl.get();        int rs = runStateOf(c);        // Check if queue empty only if necessary.        if (rs >= SHUTDOWN &&            ! (rs == SHUTDOWN &&               firstTask == null &&               ! workQueue.isEmpty()))            return false;        for (;;) {            int wc = workerCountOf(c);            if (wc >= CAPACITY ||                wc >= (core ? corePoolSize : maximumPoolSize))                return false;            if (compareAndIncrementWorkerCount(c))                break retry;            c = ctl.get();  // Re-read ctl            if (runStateOf(c) != rs)                continue retry;            // else CAS failed due to workerCount change; retry inner loop        }    }    boolean workerStarted = false;    boolean workerAdded = false;    Worker w = null;    try {        w = new Worker(firstTask);        final Thread t = w.thread;        if (t != null) {            final ReentrantLock mainLock = this.mainLock;            mainLock.lock();            try {                // Recheck while holding lock.                // Back out on ThreadFactory failure or if                // shut down before lock acquired.                int rs = runStateOf(ctl.get());                if (rs < SHUTDOWN ||                    (rs == SHUTDOWN && firstTask == null)) {                    if (t.isAlive()) // precheck that t is startable                        throw new IllegalThreadStateException();                    workers.add(w);                    int s = workers.size();                    if (s > largestPoolSize)                        largestPoolSize = s;                    workerAdded = true;                }            } finally {                mainLock.unlock();            }            if (workerAdded) {                t.start();                workerStarted = true;            }        }    } finally {        if (! workerStarted)            addWorkerFailed(w);    }    return workerStarted;}

上面方法做的事情就是将 firstTask 作为参数拿来创建一个 Worker 对象 w,然后通过 w 获得线程实例 thread,最后就是调用这个线程的 start() 方法。这里我们要明确一下:此时 Worker 对象中的 Thread 属性所持有的 Runnable 对象其实是 代码4 中新创建的 Runnable, 而我们真正的任务是在其 run() 方法中,看下面代码:

#AsyncTask.javapublic 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);        }    }}

运行 Worker.thread.start() 最終会运行上面的 run() 方法。在该 run() 方法中又会调用传递进来的参数 Runnnable 对象的 run()方法,而这个传递进来的参数其实就是 mFuture,可回头看 代码块2。好吧,请允许我先喘口气… 在前面我们已经知道 mFuture 是在 AsyncTask 的构造方法中进行初始化的。现在让我们直接跳转到 mFuture 所属类型 – FutureTask 类的 run() 方法:

#FutureTask.javapublic void run() {    if (state != NEW ||        !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))        return;    try {        Callable 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);        }    } finally {        // runner must be non-null until state is settled to        // prevent concurrent calls to run()        runner = null;        // state must be re-read after nulling runner to prevent        // leaked interrupts        int s = state;        if (s >= INTERRUPTING)            handlePossibleCancellationInterrupt(s);    }}

该方法会最終会执行 callable 对象的 call 方法。那这个 callable 是什么时候初始化的呢?还记得在 AsyncTask 的构造起中创建 mFuture 时会传递 mWorker 参数:

public AsyncTask() {    mWorker = new WorkerRunnable() {        public Result call() throws Exception {            mTaskInvoked.set(true);            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);            //noinspection unchecked            Result result = doInBackground(mParams);            Binder.flushPendingCommands();            return postResult(result);        }    };    mFuture = new FutureTask(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);            }        }    };}

这样一下就明白了,执行 callable 的 call() 方法其实就是调用上面 WorkRunnable 类中的 call() 方法。在该方法中看到了熟悉的代码:Result result = doInBackground(mParams);

原来我们的 doInBackground() 方法是在这里被调用的。当后台任务执行完后,会接着调用 postResult()

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

在这里会向主线程发送一个消息,表示后台任务已经执行完成。具体的消息处理方法如下:

 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:                // 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 {        onPostExecute(result);    }    mStatus = Status.FINISHED;}protected void onProgressUpdate(Progress... values) {    }

消息类型有两种:MESSAGE_POST_RESULT 和 MESSAGE_POST_PROGRESS,分别代表任务执行完毕(正常执行完成或被中断)和任务正在处理。

总结

好了,现在是不是对整个 AsyncTask 的工作流程有个概念啦,其实归根结底还是通过 Thread+Handler,只不过这里引入线程池的概念 ThreadPoolExecutor,这使得任务调度管理和执行效率得以提升。前面我提到了网络开源框架 AsyncHttpClient,里面已经为我们做了很多准备工作了。之后我会将我做项目时基于 AsyncHttpClient 进行二次封装的库分享给大家。尽情期待哈 ^_^

更多相关文章

  1. Android应用资源的使用方法(数组、颜色、尺寸、字符串、布尔、整
  2. 源码阅读分析 - View的Touch事件分发
  3. 随Android生命周期解绑Rxjava订阅的简单流式方法
  4. Android(安卓)Touch点击事件源码分析
  5. 【原创】Android(安卓)系统稳定性 - ANR(三)
  6. Android工程引用另外一个工程的正确/错误方法
  7. Android混合开发(一)——移动端与前端交互之JSBridge引入
  8. 简述Android(安卓)解决65536/64K方法数限制方案
  9. Android(安卓)—— 自定义View的实现方法

随机推荐

  1. App Inventor for Android(安卓)- 大家都
  2. Android下USB Accessory的实现分析
  3. Android中字体颜色的设置
  4. [Android] 开发资料收集:动态加载、插件化
  5. android studio导入 so ,jar 文件。
  6. Android单元测试全解
  7. android通过adb wireless的使用
  8. Android(安卓)Recovery模式
  9. Android知识点记录: 使用代码设置 androi
  10. Android启动过程深入解析