AsyncTask源码分析

AsyncTask类是我们在开发中经常需要用到的一个类,这个类有个最大的好处就是将耗时的操作和UI操作分开来处理,这样在这一个类中我们就可以很方便的处理耗时操作和UI操作了。
先上一个简单的例子来看看基本的用法。

public class MainActivity extends AppCompatActivity {

    private ImageView mImageView;
    private static final String URLSTRING = "https://img3.doubanio.com/view/photo/photo/public/p2360705951.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = (ImageView) this.findViewById(R.id.imageview);
        new MyAsyncTask().execute();
    }


    class MyAsyncTask extends AsyncTask<Void, Integer, Bitmap> {

        @Override
        protected Bitmap doInBackground(Void... voids) {
            URL url = null;
            HttpURLConnection conn = null;
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
                url = new URL(URLSTRING);
                conn = (HttpURLConnection) url.openConnection();
                if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    InputStream ins = conn.getInputStream();
                    int length = 0;
                    byte[] data = new byte[1024];
                    while ((length = ins.read(data, 0, data.length)) != -1) {
                        bos.write(data, 0, length);
                    }
                    byte[] buffer = bos.toByteArray();
                    return BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                conn.disconnect();
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            mImageView.setImageBitmap(bitmap);
        }
    }

}

这个例子很简单,就是加载一个网络图片,并且显示到ImageView上去。

效果如下:
这里写图片描述

下面源码的分析也从如何操作耗时操作和如何操作UI操作两个方面来分析AsyncTask。

  • 耗时操作
    对于耗时操作,AsyncTask内部是使用ThreadPool线程池来操作的。直接上源码
 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE = 1;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

CPU_COUNT、CORE_POOL_SIZE、MAXIMUM_POOL_SIZE、KEEP_ALIVE这些常量包含了cpu数量、线程池数量、最大线程池数量、同时或者的最多的线程数量,这些都是用于构造线程池执行器的参数。sThreadFactory是一个线程构造器,sPoolWorkQueue是一个容量为128的阻塞队列。这些参数最后构造了THREAD_POOL_EXECUTOR,通过这个线程池执行器,耗时的任务就可以通过阻塞队列依次的被执行。

  • UI线程操作
    UI线程的操作是通过构造了一个关联UI线程的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;
            }
        }
    }

在InternalHandler类的构造方法中,传递一个Looper.getMainLooper()参数,就可以将这个Handler关联到UI线程上,所有Handler中的处理也就分发到了UI线程上。所以我们可以利用这个Handler来执行UI操作。

现在我们可以大致得出一个结论:耗时的操作是通过线程池THREAD_POOL_EXECUTOR执行的;UI的操作是通过InternalHandler类操作的。

对于AsyncTask的使用最简单的莫过于上面的new MyAsyncTask().execute(),这个调用涉及到构造方法和executor()两个方法,下面就通过这两个方法的执行来彻底梳理一下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);
                }
            }
        };
    }

从代码中可以看到,在构造方法中,生成了一个WorkRunnable对象,WorkRunnable这个类实际上就是一个实现了Callable接口的抽象类,在call()方法中,我们调用了doInBackground()方法,并且将最终的结果通过postResult()分发出去;Callable接口并不是我们需要的,因为线程池需要Runnable的接口,所以又生成了一个FutureTask的对象用来将Callable接口转换成Runnable接口。所以构造方法的目的是生成一个mFuture的FutureTask对象。

  • executor方法
    executor方法最后调用的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;
    }

在这个方法中,最终调用了exec.execute(mFuture),exec就是sDefaultExecutor,最终调用了线程池ThreadPoolExecutor中的executor方法执行doInBackground方法,并且在这个方法执行完毕之后调用postResult()方法。

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

postResult方法调用了internalHandler中的消息处理。

   case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;

result.mTask指的就是AsynTask这个对象,结果就是调用了finish()方法。

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

最后执行了onPostExecute()这个方法,并且是通过InternalHandler在UI线程完成的。

最后总结一下:在构造方法中,将doInBackground()方法最终包装成一个FutureTask类,然后通过 execute()方法,将这个方法传递到线程池中执行;等执行完毕之后,通过InternalHandler将这个结果发送到AsyncTask的finish()方法中执行,在finish方法中执行onPostExecutor()方法。大致流程就是这样~~

posted @ 2016-07-01 01:04  豌豆豆  阅读(96)  评论(0编辑  收藏  举报