AsyncTask源码分析之Android篇

在上一篇AsyncTask源码分析中为大家做了一些基础知识的铺垫,这篇就为大家真正解析一下AsyncTask源码:
首先为大家介绍一些AsyncTask的一些特性:
1、AsyncTask在3.0版本以后默认是串行的
2、AsyncTask不能在非UI线程中创建
3、AsyncTask任务数量上限是128个
4、AsyncTask只适合短时间几秒的耗时操作,不适合长时间的
耗时操作,原因是AsyncTask默认是串行的,如果你一个操作执行几分钟,那么其他的任务就根本没有办法执行
5、每个AsyncTask创建一次只能使用一次

首先大家看一下:

   /**
     * 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
                Result result = doInBackground(mParams);
                Binder.flushPendingCommands();
                return postResult(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);
                }
            }
        };
    }

这是AsyncTask的构造方法,在上面的注释中我们看到AsyncTask必须在UI线程中创建,却没有说为什么。只是初始化了两个对象mWorker,mFuture.

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

mWorker实际上是一个实现了Callable接口的类罢了,mFuture也不过是一个FutureTask类。暂时没有发现什么用那我们接着往下看:

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

当你执行一个任务必然会调用execute方法,那这个方法最终调用的是executeOnExecutor(sDefaultExecutor, params)

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

看到这里大家一定会看到一个熟悉的方法,onPreExecute(),这个方法经常用来做一些提前的操作,这里大家明白为什么可以提前操作了,因为它允许在主线程里。这里也解释了为什么AsyncTask创建一次只能用一次,因为AsyncTask是有状态的,运行之后的状态为Running就会报错,只有状态为Pending的时候才能继续运行下去。params是传进来的参数,sDefultExecutor是什么呢?

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

这个sDefaultExector这个方法里面所有的逻辑操作都是在子线程中执行的,并且是串行的,这也是为什么AsyncTask默认是串行执行的原因所在。我来分析一下这个串行执行的奥秘。

1、FutueTask对象通过offer()方法添加进ArrayQueue数组队列中
2、mActivie == null
3、scheduleNext方法中
4、通过poll()方法取出,赋给mActivie,通过线程池ThreadPoolExecutor去执行

 public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

5、执行FutureTask里面的run()方法里面的内容,其实最终执行的是Callable()接口里面call()方法里面的内容,就是这里传入的mWorker对象里面call()方法里面的内容

 mWorker = new WorkerRunnable<Params, Result>() {
            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);
            }
        };

大家惊讶的在这里发现了我们熟悉的doInBackgroud(mParams)方法,所以doInBackgroud()内容才能在后台操作,因为这个方法是在子线程中执行的,接着讲执行的结果返回了出去,调用了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;
    }

看到postResult方法里面的内容,大家惊讶的发现了Handler的身影,我们仔细看一下getHandler()方法的源代码:

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

大家此时突然发现这个获得的Handler用的是主线程的Looper,这下大家明白为什么AsyncTask方法必须在主线程中创建了吧。在handleMessage方法里面我们看到有两种状态一种是MESSAGE_POST_PROGRESS,调用的是更新进度的方法,为什么能够直接更新UI,其实就是利用了Handler进行了线程的切换。还有另外一种状态是MESSAGE_POST_RESULT,大家看看这个状态最终调用了finish()

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

大家又看到了onPostExecte这个方法,现在大家对AsyncTask的执行过程有了基本的了解,我们回头来解析完AsyncTask串行的秘密。

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

调用完FutureTask对象的run()方法之后,谷歌的工程师在这里做了一个绝妙的处理,利用了Java当中捕获异常当中的finally绝对会执行的特性,在finally中又再次调用了sheduNext方法,形成了一个如果ArrayQueue这个方法中如果有消息就绝对会执行完成的变异递归,如果没有了,那么mActive又会立刻为null,一旦mActive为null,又会再次走刚刚那套流程。但无论如果,每次都只有一个对象被执行。这就是AsyncTask串行的秘密。

另外为大家讲述一些AsyncTask常用的API:

public final boolean cancel(boolean mayInterruptIfRunning) {
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }

其实这个就是调用了mFuture的cancle()方法,我们经常在一个Activity销毁的时候调用这个方法,免得消息没有处理完,AsyncTask因为无法得到回收。造成内存泄漏

public static void setDefaultExecutor(Executor exec) {
        sDefaultExecutor = exec;
    }

其实这边就是刚才讲的设置默认的Executor,通过设置这个可以将AsyncTask变成并发的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章