6

Android中AsyncTask的执行过程

 3 years ago
source link: http://www.androidchina.net/7736.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
Android中AsyncTask的执行过程 – Android开发中文站
你的位置:Android开发中文站 > Android开发 > 开发进阶 > Android中AsyncTask的执行过程

AsyncTask是由Android提供的一个轻量级的异步类,其内部分封装了线程池和Handler。相信绝大多数的Android开发者都接触过它,简单粗暴的就实现了异步网络请求,UI更新。在开始源码分析执行过程前,先看一张图,主要抽取了执行过程中比较关键的几个属性。

这里写图片描述

下面开始进行源码的分析,先从一段简单的示例代码开始。

public class MainActivity extends AppCompatActivity {

    private ProgressDialog dialog;

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

        dialog = new ProgressDialog(this);
        dialog.setMax(100);
        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        dialog.setCancelable(false);

        new MyAsyncTask().execute();
    }

     class MyAsyncTask extends AsyncTask<Void,Integer,Boolean> {
        private int counter=0;

        //当我们调用了execute(),即开始执行异步任务时调用,做一些初始化操作
        @Override
        protected void onPreExecute() {
            dialog.show();
        }

        //在这里处理所有的耗时任务,会在子线程中执行,返回的结果会传递给onPostExecute()中的参数
        @Override
        protected Boolean doInBackground(Void... voids) {
            while (true){
                counter++;
                //获取当前任务进度,会执行onProgressUpdate,更新状态
                publishProgress(counter); 
                try {
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (counter>=100){
                    break;
                }
            }
            return true;
        }

        //处理来自publishProgress的信息
        @Override
        protected void onProgressUpdate(Integer... values) {
            dialog.setProgress(values[0]);
        }

        //对doInBackground返回的结果进行处理
        @Override
        protected void onPostExecute(Boolean b) {
            if (b){
                dialog.dismiss();
            }
        }
    }
}

根据上面的代码,可以知道AsyncTask需要在主线程中实例化,执行execute();每个方法的作用已经注释,接下来说明下AsyncTask<>中的三个参数:

第一个参数:执行execute()需要输入的参数,会在doInBackground()中处理后台任务时使用。
第二个参数:如果需要清楚后台任务的进度,可以通过这个参数转换成进度单位,在onProgressUpdate()中显示。
第三个参数:这个参数是doInBackground()在任务完毕时返回的参数,会传递给onPostExecute().

蓄能完毕,面对疾风吧~~

1、我们从上面的示例代码获取MyAsyncTask示例开始,这时看看AsyncTask源码构造函数中做了什么事:

public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? 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);
                }
            }
        };
    }

啥也没看出来,只知道初始化了三个变量值^_^。细分析下:还是有的么,在初始mFuture 时mWorker作为参数传入,从上面图中可以知道mWorker是一个Callable(WorkerRunnalbe)对象,重写了call()方法,在call方法里面可以看到一个关键性的字眼doInBackground,这就说明(顺利进行的情况下),任务的执行最终会调用mWorker的call方法。打完,收工!

如果你以为到这就结束了,送哥们两个字“呵呵”。折腾的还在后面呢。

2、来,一起看看为什么最终会调用mWorker的call方法。上面我们已经获取了实例,那下面就是开始执行了, new MyAsyncTask().execute();研究下execute()做了什么事情。

  public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return 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;
    }

进去execute里面,发现又调用了executeOnExecutor;可以看到,在executeOnExecutor里面,把AsyncTask的状态为RUNNING,然后调用onPreExecute(),这个地方依然是执行在主线程当中的,因此,可以在onPreExecute中做一些初始化操作。

mWorker.mParams = params; 把传入的参数保存在mWorker中;

跟着就到了exec.execute(mFuture); exec即是传入的sDefaultExecutor,看下面的代码就知道这个是什么了。

  public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

根据上面的代码,exec.execute(mFuture)其实就是执行了SerialExecutor的execute方法。脑海中时刻幻想着最上面的图片(^▽^)

3、接下来我们看下execute里面做了什么事。

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

这时,我们可以看出,执行SerialExecutor的execute时会把mFuture加入mTasks队列中。然后通过scheduleNext一个接一个的取出来,从这里我们就可以得知,AsyncTask是串行的执行任务。而SerialExecutor 这个线程池只是给AsyncTask任务排队。真正执行任务其实是THREAD_POOL_EXECUTOR线程池,看下面代码:

  public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

这里暂时先不讲ThreadPoolExecutor这个类,后续会发一篇针对线程池的文章。再回看THREAD_POOL_EXECUTOR.execute(mActive)这行代码,启动真正的任务执行时,传入mActive,这个是从mTasks中取出来的,也就是说THREAD_POOL_EXECUTOR执行任务时,会执行mFuture.run();mFuture是FutureTask类的实例。

4、我们看下FutureTask中的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);
        }
    }

根据上面代码,我们可以看到FutureTask类的run方法里面获取了一个Callable对象,调用了c.call()执行。而上面AsyncTask的构造函数中,初始化FutureTask对象mFuture时,传入了WorkerRunnable对象mWorker。

突然之间,脑门大开,AsyncTask的执行过程原来这么………剩下两字儿哥们幻想下(^▽^)!

5、到此,我们已经知道了AsyncTask是怎么处理后台任务的了,接下来就是对结果的处理了,看WorkerRunnable的call方法里面做了什么事,也就是在初始化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;
            }
        };

重新复制了构造函数的代码,大家就不用翻上去看了。不用说谢谢(^▽^)!
在call方法中执行doInBackground时返回一个result,然后 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;
    }

  private static class AsyncTaskResult<Data> {
        final AsyncTask mTask;
        final Data[] mData;

        AsyncTaskResult(AsyncTask task, Data... data) {
            mTask = task;
            mData = data;
        }
    }

通过上面代码可以发现,把result封装在AsyncTaskResult中,通过handler发送消息至handleMessage中处理。getHandler()返回的是,已经在构造函数中初始化好的mHandler;

6、接下来再看下mHandler的初始化过程:

  mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

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

 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
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                //更新任务进度
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }

根据上面的代码,我可以看到,最终的结果是在AysncTask的finish方法中完成的。一起看看finish里面的代码:

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

在这里通过isCancelled()判断当前AsyncTask的任务是否已经取消,如果没有,则通过onPostExecute()处理相应结果。

AsyncTask的执行过程到这里已经基本完毕了。这时我们应该知道为什么要在主线程里面去创建AsyncTask对象,并调用execute了。这次分析的AsyncTask是源码6.0以上的,对于一些低版本的会有区别,在这方面网上已经有好多博客有写,这里就不在赘述。关于AsyncTask在开发中的一些缺陷和需要注意的问题:在这里给大家提供一个链接,点击这里

转载请注明:Android开发中文站 » Android中AsyncTask的执行过程


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK