Android在框架层提供了异步任务类,AysncTask,用于执行后台任务,并将执行结果更新到UI线程。为什么要用异步任务呢?这是因为如果某个任务太耗时间的话,会阻塞UI主线程,而我们知道UI线程如果阻塞5秒的话,就会发生ANR(Application No Response)错误 ,就算没有发生,主界面上看起来也会卡卡的,这显然用户体验就不太好了。

而AsyncTask类则在不影响UI线程的情况下,另起子线程去做那些耗时比较久的任务,比如我们在TodoList中去读取图片这种情况,然后将处理后的结果再更新到UI线程,从而达到更好的用户体验。

下面是AsyncTask类的定义:

public abstract class AsyncTask<Params, Progress, Result> {private static final String LOG_TAG = "AsyncTask";...

从上面的代码可以看出,AsyncTask是一个抽象类,所以在使用AsyncTask的时候,我们要继承它,实现一个子类,并实现其中一个方法,如下:

 class LoadImageTask extends AsyncTask<String, Void, ImageView>{@Overrideprotected ImageView doInBackground(String... params) {String photoImagePath = params[0];Bitmap bitmap = BitmapReader.readBigBitmapFromFile(photoImagePath,REQ_WIDTH);ImageView imageView = Helper.createImageViewFromBitmap(DetailActivity.this, bitmap);return imageView;}protected void onPostExecute(ImageView result) {imageViews.add(result);refreshGallery();}}

对照 AsyncTask的三个参数,Params, Progress和Result,是泛型参数。

1)Params :参数,比如例子中定义的String类型,指向一个Image的路径,这是传给AysncTask的doInBackground方法。

2)Progress:这是在执行过程中会用到的一个参数,一般在显示进度的时候会用到,在例子中不会用到,所以可以在这里指定为Void。

3)Result:这是执行的结果对象,会作为onPostExecute方法的参数,在UI线程中处理。

由上面的例子也可以看到,一般我们实现的这个子类,要实现其中的两个方法

1)doInBackground:这个方法,其实是在另外一个线程中执行的。

2)onPostExecute:而这个方法却已经回到UI线程中来执行,所以可以在这里将上一个方法中执行所得的结果在这里更新到UI线程中。

那么这里面的机制是怎么样的呢,我们就来深入地看一下,也学习一下吧。

首先我们来看一下在Activity中,我们是怎么样来使用我们这个AsyncTask的吧,代码如下:

 @Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data){        if (requestCode == REQUEST_FOR_CAMERA) {if(resultCode == RESULT_OK){isPhotoTaken = true;           photoFileNames.add(tempPhotoFileName);          }} else if (requestCode == REQUEST_FOR_GALLERY) {if(resultCode == RESULT_OK){isPhotoTaken = true;          ContentResolver resolver = getContentResolver();Uri uri = data.getData();tempPhotoFileName = Helper.getImagePath(resolver, uri);photoFileNames.add(tempPhotoFileName);               }}new LoadImageTask().execute(tempPhotoFileName);//调用其execute方法}

在TodoList的小demo中,在相机或者图库返回来图片的路径之后,我们就会调用AsynctTask的execute方法了,那么这里就是入口了。

进入AsyncTask类中,找到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;}

在这个方法中,我们可以发现,AsynctTask定义了一个mStatus的成员变量,来表示异步任务的运行状态,分别是pending,running和finished,但只有处于pending状态的AsnycTask才能被执行。当状态是Pending的时候,就会继续执行,将状态变成running,这样能够保证AsyncTask只会被执行一次。

接着会调用onPreExecute方法做一些处理工作,这个方法其实我们也可以在子类中自己实现,如果有什么需要处理的话,一般不用。

然后我们发现,我们传进来的参数params会被传给mWorker,然后会有一个executor来执行execute的方法,并且执行的参数是一个mFuture对象。那么这两个东西是什么呢?

接着看如下代码:

    public AsyncTask() {mWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {mTaskInvoked.set(true);Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedreturn postResult(doInBackground(mParams));}};mFuture = new FutureTask<Result>(mWorker) {@Overrideprotected 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);}}};}

mWorker是一个WorkerRunnable对象,而实际上WorkerRunnable是AsyncTask的一个抽象内部类,实现了Callable接口,如下:

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

而在上面的赋值过程,通过匿名类实现了WorkerRunnable,并其call方法中将线程优先级调整为后台线程,然后会执行 doInBackground方法,不过现在还没执行,咱们再看看FutureTask对象,下面是它的构造函数:

    public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();sync = new Sync(callable);}

而FutureTask是Java多线程模型的一部分,其间接地实现了Runnable(线程属性)接口和Future(异步任务)接口,而在上面的executeOnExecutor方法中,正是将mWorker(实现了Callable接口)对象传给它了,并被其封装到成员变量sync中,这样它们就共同表示了一个异步任务,到这里,一个异步任务也就创建完成了。

从上面executeOnExecutor的方法,也可以看到,真正执行execute是一个Executor,而在AsyncTask中,其实是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();//在新线程中调用了我们上面传进来的FutureTask的run方法} finally {scheduleNext();}}});if (mActive == null) {scheduleNext();}}protected synchronized void scheduleNext() {if ((mActive = mTasks.poll()) != null) {THREAD_POOL_EXECUTOR.execute(mActive);}}}

从上面,我们可以看到execute方法的参数就是一个Runnable,其实也就是FutrueTask了,在这里,它会被封装到一个新的线程中作为一个任务添加到mTasks队列中,至于下面如何在THREAD_POOL_EXECUTOR中去执行mTasks我们就不再深入下去了,我们就来看看FutureTask的run方法,如下:

    public void run() {sync.innerRun();}

我们发现,它调用的是sync.innerRun(),那么Sync的innerRun方法又干了什么呢?

        void innerRun() {if (!compareAndSetState(READY, RUNNING))return;runner = Thread.currentThread();if (getState() == RUNNING) { // recheck after setting threadV result;try {result = callable.call();} catch (Throwable ex) {setException(ex);return;}set(result);} else {releaseShared(0); // cancel}}

我们发现,它调用了callable的call方法,啊,我们终于来到了mWorker的call方法,回过头看,不就是在那里调用了doInBackground方法的吗?所以,我们可以确定,doInBackground的确是在一个新的线程中执行的,并且是一个后台线程。

但同时我们发现,其执行完之后,是作为一个参数传递给postResult的,继续看下去:

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

可以看到,在这里是利用了sHandler来发送异步消息的,而sHandler是在AsynctTask中定义的,如下:

private static final InternalHandler sHandler = new InternalHandler();

InternalHandler定义如下

    private static class InternalHandler extends Handler {@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {AsyncTaskResult result = (AsyncTaskResult) msg.obj;switch (msg.what) {case MESSAGE_POST_RESULT:// There is only one resultresult.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS:result.mTask.onProgressUpdate(result.mData);break;}}}

我们可以在这里发现,如果是MESSAGE_POST_RESULT,则会调用mTask的finish方法,然后就结束了,而如果是MESSAGE_POST_PROGRESS,则会调用 onProgressUpdate方法,那么,很显然这个mTask应该就是我们定久的AsyncTask了吧。我们看看AsyncTaskResult是什么先,

    @SuppressWarnings({"RawUseOfParameterizedType"})private static class AsyncTaskResult<Data> {final AsyncTask mTask;final Data[] mData;AsyncTaskResult(AsyncTask task, Data... data) {mTask = task;mData = data;}}
}

我们发现,在上面传进来的AsyncTaskResult的参数task的正好就是this,而它又赋值给了mTask的,所以说明,这个mTask就是我们在Activity中定义的LoadImageTask了,而它是在主线程中定义的,那么很显然,它的finish方法也是在主线程,也就是UI线程中执行的了,再来看看这个finish方法:

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

在这里,我们终于看到了onPostExecute方法的调用了,这说明了,onPostExecute就是在UI线程中干活的了。最后mStatus也被设计成FIINISHED了,这个异步任务也就结束了。

嗯,关于AsyncTask的基本原理到这里也就结束了。

Android中从源码分析关于AsyncTask的使用相关推荐

  1. Android多媒体框架(3)—— libstagefright中MediaCodec源码分析

    libstagefright中MediaCodec源码分析 和前两篇一样,我们按照MediaCodec的各个状态来分析libstagefright中MediaCodec的源代码. configure ...

  2. CTS(11)---android自动化测试CTS源码分析之一

    android自动化测试CTS源码分析之一 1, 概述 CTS(Compatibility Test Suite)全名兼容性测试,主要目的就是让Android设备开发商能够开发出兼容性更好的andro ...

  3. android agps,Android应用开发Android GPS ——AGPS源码分析及配置

    本文将带你了解Android应用开发Android GPS --AGPS源码分析及配置,希望本文对大家学Android有所帮助. " Android Framework GPS --AGPS ...

  4. android gps源码分析,Android编程之Android GPS ——AGPS源码分析及配置

    本文主要介绍了Android编程的Android GPS --AGPS源码分析及配置,通过具体的分析以及源码,向大家展示了这些,希望对大家学习Android编程有所帮助. 1:冷启动指令: locat ...

  5. zipline中TradingCalendar源码分析

    zipline中TradingCalendar源码分析 1 TradingCalendar 交易日历 2 依赖项 3 canonicalize_datetime 时间进行格式化转换 4 get_non ...

  6. JDK7中HashMap源码分析

    文章目录 JDK7中的HashMap 一.JDK7中HashMap源码中重要的参数 二.JDK7中HashMap的构造方法 三.JDK7中创建一个HashMap的步骤 四.JDK7中HashMap的p ...

  7. android(cm11)状态栏源码分析(一)

    版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/50216563 (一):写在前面 最近由于工 ...

  8. Android之HandlerThread源码分析和简单使用(主线程和子线程通信、子线程和子线程通信)

    1.先熟悉handler方式实现主线程和子线程互相通信方式,子线程和子线程的通信方式 如果不熟悉或者忘记了,请参考我的这篇博客     Android之用Handler实现主线程和子线程互相通信以及子 ...

  9. Android——RIL 机制源码分析

    Android 电话系统框架介绍 在android系统中rild运行在AP上,AP上的应用通过rild发送AT指令给BP,BP接收到信息后又通过rild传送给AP.AP与BP之间有两种通信方式: 1. ...

最新文章

  1. 【翻译】Ext JS 5:为不同设备设置不同的主题
  2. 爱上MVC~ajax调用分部视图session超时页面跳转问题
  3. 【NLP实战】Task1 数据集探索
  4. 第二节:垃圾回收期算法简介
  5. java安全编码指南之:ThreadPool的使用
  6. 介绍一个能避免 CORS 错误的 Chrome 扩展 - Moesif Origin CORS Changer
  7. 关于PHP默认Expires: Thu, 19 Nov 1981...的故事
  8. java基础输入_java基础之标准输入
  9. jsp+servlet+mysql简单实现用户登陆注册
  10. 推荐的字符与字符串处理方式
  11. Git 协同开发流程
  12. Unity3D基础20:游戏打包发布
  13. 邮箱服务申请数字证书
  14. c语言 16 16 字库,16位汉字显示屏的字库软件(点阵字库)
  15. java fup spring
  16. “New”一个完美对象,再来好好面向对象
  17. 寒霜3引擎再造经典极品飞车18
  18. LetCode#69(JAVA)给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去.
  19. Ubuntu 20.04 源码编译Paddle2.2.2
  20. 新手学平面设计都会遇到哪些问题

热门文章

  1. 公司采购 流程flowable例子
  2. 杭电 hdu 3343
  3. Solr基础,在Eclipse中运行Solr
  4. uva-10341-二分法
  5. 信息系统项目管理师---运筹学计算
  6. Java 集合深入理解(15):AbstractMap
  7. Introducing Microsoft Sync Framework: Sync Services for File Systems
  8. sharepoint2007就地升级2010系列(三)升级系统
  9. Android开发小结Part2:目录
  10. 程序员:下一次面试前你需要准备的五个基本步骤