欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

从应用角度看Android源码 - 扒开AsyncTask的祖坟

程序员文章站 2024-02-26 22:41:16
...

本想写一下源码的获取和编译的过程,无奈出租房的网络实在太差,没能把源码下完整,暂且跳过这一步,假设我已经写好了.这一篇就学习一下AsyncTask,这是一个比较简单的知识点,作为源码开发的热身小甜点.

AsyncTask是一个轻量级的异步操作类,我写了一个极其简单的Demo代码如下

public class MainActivity extends Activity {

    private final String TAG = "testlog";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //实例化一个AsyncTask
        new AsyncTask<Integer, Integer, Integer>() {

            //根据名字可以了解到这个函数可以在执行doInBackground函数之前做一些初始化的工作
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                log("onPreExecute: ");
            }
            //进行异步操作的函数,该函数不在主线程执行
            @Override
            protected Integer doInBackground(Integer... integers) {

                log("doInBackground: init  > " + integers[0]);
                int i = 5;
                while (i-- > 0) {
                    log("doInBackground: " + i);
                    //调用该函数可以更新进度条,会调用onProgressUpdate()函数
                    publishProgress(i);
                    //模拟耗时操作
                    sleep(500);
                }
                return i;
            }
            //执行在主线程里
            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
                log("onProgressUpdate: " + values[0]);
            }
            //异步操作执行完成后调用该方法
            @Override
            protected void onPostExecute(Integer integer) {
                super.onPostExecute(integer);
                log("onPostExecute: " + integer);
            }
        }.execute(13);

    }

    private void sleep(long time) {
        try {
            Thread.sleep(time);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void log(String msg) {
        Log.i(TAG, msg + " > " + Thread.currentThread());
    }

执行结果如下

04-14 13:02:10.250 I: onPreExecute:  > Thread[main,5,main]
04-14 13:02:10.251 I: doInBackground: init  > 13 > Thread[AsyncTask #1,5,main]
04-14 13:02:10.255 I: doInBackground: 4 > Thread[AsyncTask #1,5,main]
04-14 13:02:10.264 I: onProgressUpdate: 4 > Thread[main,5,main]
04-14 13:02:10.757 I: doInBackground: 3 > Thread[AsyncTask #1,5,main]
04-14 13:02:10.758 I: onProgressUpdate: 3 > Thread[main,5,main]
04-14 13:02:11.259 I: doInBackground: 2 > Thread[AsyncTask #1,5,main]
04-14 13:02:11.260 I: onProgressUpdate: 2 > Thread[main,5,main]
04-14 13:02:11.761 I: doInBackground: 1 > Thread[AsyncTask #1,5,main]
04-14 13:02:11.762 I: onProgressUpdate: 1 > Thread[main,5,main]
04-14 13:02:12.263 I: doInBackground: 0 > Thread[AsyncTask #1,5,main]
04-14 13:02:12.264 I: onProgressUpdate: 0 > Thread[main,5,main]
04-14 13:02:12.765 I: onPostExecute: -1 > Thread[main,5,main]

接下来就去挖坟,看看这是一个怎样的流程,首先从AsyncTask的入口execute着手

  @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

在execute里面调用了executeOnExecutor()函数,不过多了一个参数sDefaultExecutor,先看看这个参数是个什么鬼
  private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
  public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    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);
            }
        }
    }
原来他是一个实现了Executor接口的类,知道他是一个类就可以了.再回过来继续扒坟,看看executeOnExecutor()又做了什么
    @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;
    }

这里面先判断了一下当前的状态,怪不得这个异步任务只能执行一次execute(),原来在这块根据状态抛出了异常.判断状态之后调用了onPreExecute(),这是AsyncTask回调的第一个函数,注意这个  @MainThread 注解的意思是这个函数必须在主线程中执行.回调onPreExecute()之后又调用了exec.execute(mFuture),看看mFuture是啥,

mFuture = new FutureTask<Result>(mWorker) 

public class FutureTask<V> implements RunnableFuture<V> 

public interface RunnableFuture<V> extends Runnable, Future<V>
看到这里可以了解到mFuture是实现了Runnable接口的类的实例。根据我对AsyncTask的了解这个exec.execute(mFuture)的操作会跟doInBackground()这个回调扯上匪夷所思的关系.凡是要讲究证据,再继续往下找线索.这个exec就是上面找的sDefaultExecutor,不在重复粘贴代码了,可以去上面看,看看他的execute()方法都干了啥,让在里面又调用了mTasks.offer(),mTasks是ArrayDeque类型,这句是把任务推进队列。接下来就调用了       scheduleNext();

  protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }

这个函数是把队列中的第一个任务放进线程池,这样一来在条件允许的情况下会执行该任务,也就是会在新的线程里回调mFuture的的run方法。下面研究一下FutureTask类

    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
根据上面可以知道mFuture实例中的callable变量是mWorker实例,再看看他的run函数,
 public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            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);
            }
        } 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);
        }
    }

在这里调用的mWorker的call()函数,在回到AsyncTask类看看mWorker是什么样子的。

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

原来在这里调用了doInBackground(),因为他是由mFuture所在线程调用的,也就是线程池里的线程,并非在主线程上运行,所以这里不能出现直接更新UI的操作。在最后还调用了  postResult(result);

    private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
他向一个handler发送了一条MESSAGE_POST_RESULT类别的消息,这个handler在哪呢
    private static Handler getHandler() {
        synchronized (AsyncTask.class) {
            if (sHandler == null) {
                sHandler = new InternalHandler();
            }
            return sHandler;
        }
    }

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

原来他是AsyncTask里的handler,他接收到MESSAGE_POST_RESULT消息的时会调用finish()函数

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

在finish()里调用了 onPostExecute(result);因为是AsyncTask的handler调用的finish()函数,因此该函数是运行在AsyncTask所在的线程里的,也就是主线程。至此AsyncTask的三个函数

protected void onPreExecute()
protected Integer doInBackground(Integer... integers)
protected void onPostExecute(Integer integer) 

都已经出现了,还差一个protected void onProgressUpdate(Integer... values),这个函数通常是为了更新进度条的,与他有直接关系的就是publishProgress(Progress... values)

    @WorkerThread
    protected final void publishProgress(Progress... values) {
        if (!isCancelled()) {
            getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
这个函数向handler发送了一条MESSAGE_POST_PROGRESS类别的消息,handler接收到该类别消息后会调用onProgressUpdate,这样就会更新进度条了,到这里onProgressUpdate()也出现了,扒坟结束。