AsyncTask机制详解

作者: fefg_27872 | 来源:发表于2016-04-15 16:28 被阅读271次

    先把AsyncTask的基本用法熟悉一遍

       class MyAsyncTask extends AsyncTask<Void, Integer, String> {
        @Override
        protected void onPreExecute() {
            //准备一些初始化操作
        }
    
        @Override
        protected String doInBackground(Void... params) {
          //后台操作
        }
    
        @Override
        protected void onProgressUpdate(Integer... values) {
           //更新进度
        }
    
        @Override
        protected void onPostExecute(String s) {
          //得到后台操作返回的结果
        }
    }
    
    new MyAsyncTask().execute();  
    

    Void,Integer,String三个类型分别是在做后台操作时传入的参数, 更新的进度, doInBackground操作里返回的结果。

    上面就是基本的用法,接下来进入正题分析AsyncTask的源码.
    首先我们new了一个MyAsyncTask的实例。那么AsyncTask的源码里做了什么呢?

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

    可以看出是实例化了一个WorkerRunnable对象,一个FutureTask对象。我们先不管这2个对象有什么用。细心的同学可以发现call()这里调用了doInBackground方法。这里的疑问我们先放下。
    然后看我们new完一个MyAsyncTask后我们执行了execute()方法。我们到源码了看execute()执行了什么。

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

    就一段代码,
    我们看到底 executeOnExecutor方法里到底执行了什么。

      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()方法露面了,确实是onPreExecute()最先执行。
    然后我们看到 exec.execute(mFuture)这段代码。这里显然可以看出sDefaultExecutor执行了execute方法。继续努力,找出sDefaultExecutor的execute方法。我们发现这个sDefaultExecutor其实就是实现了Executo的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);
            }
        }
    }
    

    r.run()的r就是上面的mFuture。还记得我在文章开头说的WorkerRunnable对象,FutureTask对象吗?在创建AsyncTask的时候就已经实例化了mFuture。所以这里
    其实就是执行了mFuture的run方法。那么问题来了,在哪里能看出run方法里做了什么鬼东西呢?首先我们可以看出mFuture是一个FutureTask对象,我们来看看他的构造函数

     public
     FutureTask(Callable<V> callable) {
    
    }
    

    在实例化的时候

    mFuture = new FutureTask<Result>(mWorker)
    

    而WorkerRunnable又实现了Callable这个接口.
    讲到这里大家或许已经明白了,run方法里执行的是mWorker里的call() 方法。

    而在call() 方法里有这样的一段代码

    return postResult(doInBackground(mParams));
    

    哈哈,doInBackground出现了。这里的mParams就是我们传入的参数,并且返回了postResult的返回值。那postResult又是什么呢?

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

    没错你没有看错,其实AsyncTask内部也是通过Handler来进行线程间通信的。在这里我们可以看到在doInBackground返回结果后postResult通过Handler发送了一个MESSAGE_POST_RESULT消息。getHandler()返回的就是这个InternalHandler。

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

    然后我们看在处理MESSAGE_POST_RESULT消息时做了这样的一件事情

       result.mTask.finish(result.mData[0]);
    

    继续看源码

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

    哈哈豁然开朗啊, 出现了 onPostExecute,可以看到在这里把doInBackground的返回值给了onPostExecute。然后把状态设置为 Status.FINISHED

    讲到这里基本的流程都已经讲完了,但是我想纠正网上大多是的帖子关于这个AsyncTask其实就是Thread和Handler的结合的说法。更准确的说法是FutureTask和Handler的结合。为什么?
    因为Thread的run方法返回值是void。而我们看AsyncTask的源码里的call() 方法里是返回了后台操作结果,我们再看,源码里有这样的一个方法

    postResultIfNotInvoked(get());
    

    而这个get()我们看

     public final Result get() throws InterruptedException, ExecutionException {
        return mFuture.get();
    }
    

    其实就是返回了FutureTask的执行结果,也就是call()方法返回结果。

    因此用Thread是达不到这种要求的。

    基本流程大概就是这样。谢谢各位看官,欢迎拍砖!!!

    相关文章

      网友评论

        本文标题:AsyncTask机制详解

        本文链接:https://www.haomeiwen.com/subject/qljnlttx.html