AsyncTask源码分析

来源:互联网 发布:蚂蚁金服规模 知乎 编辑:程序博客网 时间:2024/04/29 23:34

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()方法。大致流程就是这样~~

0 0