AsyncTask来源分析(一)
于android开发过程AsyncTask我会经常处理它。在网上,也有很多的其描述,因此,这里是不是说的用法,直接写自己的学习经验,以及它的一些浅显的认识,忘记错批评。
AsyncTask它是一个抽象类。它提供了一个抽象方法doInBackground为了提供子类实现,用者自己来实现一些比較耗时的工作。
在AsyncTask的生命周期中任务分为三个状态,由变量mStatus来控制,mStatus为枚举类型,枚举类的名称为Status:
PENDING状态:标志这个任务还没有被运行过,该状态在定义状态变量mStatus的时候就被初始化了。private volatile Status mStatus = Status.PENDING;
RUNNING状态:标志这个任务已经被运行 ,当你调用execute运行任务的execute的时候会设置mStatus = RUNNING;
FINISHED状态:在运行finish(Result result)方法的时候会设置mStatus = FINISHED。至于finish()方法的运行时机是任务运行完以后有handler发送一条相关信息,然后在handleMessage里面调用。其实onPostExecute就是在finish里面被调用的。
这三个状态的作用是防止一个AsyncTask的对象多次调用execute方法(其实AsyncTask的一个对象仅仅能被运行一次就是通过Status枚举来控制的),比方当前的AsynTask对象的mStatus为RUNNING或者FINISHED的时候你再调用execute方法的时候就会抛出异常了。看看execute的代码就能够知道:
/**
* 运行任务的入口方法
* @param params
* @return
*/
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)");
}
}
//标志任务正在运行。假设再次调用该对象的execute方法的话。会走517行代码逻辑
mStatus = Status.RUNNING;
//任务开启前运行的方法,此时仍然在UI线程中
onPreExecute();
//保存參数
mWorker.mParams = params;
//运行任务
exec.execute(mFuture); return this;
}
看executeOnExecutor方法,能够知道当第一次调用execute方法的时候executeOnExecutor里面的if条件是不成立的。当再次调用execute方法的时候if条件成立,然后就会抛出异常。
通过观察这种方法,能够发现非常多的信息,比方onPreExecute()方法就是先于其它方法运行,此时运行onPreExecute方法的时候仍在在UI线程中,所以我们能够重写这种方法以实如今运行任务之前进行其它处理的问题:比方显示载入滚动栏等。接着会运行exec.exeute(mFuture)方法来在UI线程上开启一个新的线程来运行耗时的任务:也就是运行你重写的doInBackground()方法。我们知道AsyncTask的doInBackgound方法是有返回值的,这个返回值能够传给onPreExecute(Reusult
result)方法,然后做详细的处理。也就是我们会从线程中获取一个返回值。
在细致分析之前先说几个多线程编程的几个相关的类:
Callable:为接口提供了一个call()方法,实现该接口的类可作为被其他线程运行的任务,这点和Runnable一样。
与Runnable的run方法不同的是call()方法是有返回值的(Callable就相当于一个有返回结果的Runnable),所以Callable能够用来运行那些存在延迟计算的任务。鉴于AsyncTask的目的有时候就是用来运行耗时的任务而且用该任务的运行结果来改动UI,所以能够想象的出AsyncTask里面肯定会有Callable的身影。在开发中使用AsyncTask的时候肯定会重写doInbackgound()方法。把耗时的任务放在里面运行,其实doInBackground方法就是在一个Callable的call方法里面运行的,而且利用到了Callable能够有返回值得这一特性来把doInBackground的返回值返回并由FutureTask来获取到这一个返回结果,然后经过一系列的辗转终于交给onPostExecute方法来处理。
一句废话:Callable能够返回计算结果,这个结果并不仅仅是一个数字。事实上结果能够是一个基本类型,也能够是返回一个对象当然也能够返回一个集合。
FutureTask:表示一种抽象的可生成结果的计算,它表示的计算结果是通过Callable来实现的。FutureTask将计算结果从运行计算的线程传递到获取这个运算结果的线程(摘自Java并发编程实践).能够通过FutureTask的get()方法来获取任务的计算结果.当中get()并非马上就能够得到运算结果:假设任务已经完毕运算的话。就会马上返回结果。否则get方法将会被堵塞直到任务完毕后返回运算结果(当然也可能产生异常).通过查看它的源代码能够发现FutureTask提供了一个空的方法done(),该方法在任务线程运行完的时候调用。所以程序猿自己能够写一个FutureTask的子类来重写这种方法来处理任务线程运行完后的逻辑。
当然这个在AsyncTask的源代码中得到了体现。注意FutureTask在进入完毕状态之后,该FutureTask会永远停止在这个状态上(不会被再次运行);通过观察AsyncTask的源代码能够知道,代码中的FutureTask仅仅有在构造器中初始化了一次,源代码中并没有给该类提供了再次初始化FutureTask的方法所以这也是为什么AsyncTask仅仅会被运行一次的原因。同一时候,FutureTask另一个cancel(boolean)的方法能够用来取消正在运行的任务。
实际上AsyncTask的取消任务的方法就是简单的调用FutureTask的cancel方法来完毕的。总结:一般FutureTask用来运行比較耗时的计算。在任务运行的过程中也能够调用cancel方法来强制取消任务的运行。同一时候它能够让程序猿知道任务线程运行完的时机并能够获取任务线程返回的结果。然后用这个结果在主线程中做一些处理。比方在AsyncTask的onPostExecte方法中就能够用返回的结果来改动UI线程的界面。
通过上面的说明以及AsyncTask的源代码能够总结出一下几点:
1.无论你重写不重写onPreExecute()方法,这种方法必然先运行。
2.doInBackground方法交给一个Callable的call方法运行,而且通过FutureTask的get方法获取
3.当doInBackground方法执行完的时候,FutureTask的done方法中会通过Handler发送一条消息,该消息绑定了doInBackground执行的结果。然后在
handleMessage方法中进行处理,也就是交给了onPostExecute方法进行处理
带着上面的几点,先看看Callable和FutureTask的初始化的位置以及详细都它们是怎么处理doInBackground()的,源代码例如以下:
public AsyncTask() {
初始化mWorker
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//设置控制变量为true
mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
//doInBackground方法再此运行
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是AsyncTask的抽象的嵌套内部类,它实现了Callable接口。
在call()方法中会运行postResult()方法。该方法的參数正是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;
}
能够看到它发送了一条message,那么就看看该message在Handler的handleMessage方法里面是怎么处理的。
private static class InternalHandler extends Handler {
@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;
}
}
}
result.mTask.finish(result.mData[0]);调用了AsyncTask的finish方法。就如前面所说finish方法体里面正好调用了onPostExecute方法,finish方法例如以下
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
//onPostExecute在此处调用
onPostExecute(result);
}
//设置任务的状态为FINISHED
mStatus = Status.FINISHED;
}
至此一个AsyncTask的异步任务就会运行完成。还有个FutureTask的done方法没说明。done()方法调用了postResultIfNotInvoked(get()),其方法例如以下
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
能够看出当if条件成立的时候仍然会运行postResult方法。
查看FutureTask的源代码可知在调用cancel()方法取消任务的时候会运行这个done()方法,在发生异常的时候相它会使用这种方法运行
待续,如果错了,欢迎批评
版权声明:本文博主原创文章,博客,未经同意不得转载。
AsyncTask来源分析(一)的更多相关文章
- Android `AsyncTask`简要分析
AsyncTask简要分析 经典异步任务:AsyncTask,使用场景有:批量下载,批量拷贝等.官方文档就直接给出了一个批量下载的示例. private class DownloadFilesTask ...
- Android AsyncTask 源代码分析
AsyncTask源代码分析 public abstract class AsyncTask<Params, Progress, Result> { //日志TAG private sta ...
- Android异步任务处理框架AsyncTask源代码分析
[转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 引言 在平时项目开发中难免会遇到异步耗时的任务(比方最常见的网络请求).遇到这样的问题.我 ...
- 【JUnit4.10来源分析】6 Runner
org.junit.runner.Runner它是JUnit作业引擎.它在许多类型的支持下的.处理试验和生产(Description).Failure和Result和其它输出. Runner参见图主类 ...
- 【JUnit4.10来源分析】0导航
JUnit靠GOF 中的一个Erich Gamma和 Kent Beck 单元测试框架编写一个开源,yqj2065分析JUnit的主要目的是源 中学习对设计模式的运用. JUnit也是一个学习Java ...
- SDL2来源分析3:渲染(SDL_Renderer)
===================================================== SDL源代码分析系列文章上市: SDL2源码分析1:初始化(SDL_Init()) SDL2 ...
- SDL2来源分析7:演出(SDL_RenderPresent())
===================================================== SDL源代码分析系列文章上市: SDL2源码分析1:初始化(SDL_Init()) SDL2 ...
- JUnit4.8.2来源分析-2 org.junit.runner.Request
JUnit4.8.2源代码,最为yqj2065兴趣是org.junit.runner.Request,现在是几点意味着它? ①封装JUnit的输入 JUnit4作为信息处理单元,它的输入是单元測试类- ...
- ftp server来源分析20140602
ftp server学习位和源代码分析片 记录自己的第一个开源的分析过程: 从源代码:野狐灯(我接下来的几篇文章是从源头:野狐灯,每个以下哪项不是他们设置.) 20140602 Ftp的源码目录例如 ...
随机推荐
- 【Android进阶】Android面试题目整理与讲解(二)
1. ArrayList,Vector, LinkedList 的存储性能和特性 ArrayList 和 Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们 ...
- [模式识别].(希腊)西奥多里蒂斯<第四版>笔记8它__模板匹配
在语音识别方面,同样的话都是同一个人,每次说的情况是不同的,难以识别.本章是定义如何适应不同的情况有不同的特性指标. 1,基于最优路径搜索的度量:①贝尔曼最优性原则和动态编程②编辑距离(The E ...
- bin home
bin=$(cd `dirname $0`;pwd)home=$(dirname $bin)
- 给Ubuntu安装KDE桌面 [转]
自ubuntu5.10发布以来,我非常难得的让她在我的硬盘上顽强生存了近3个月,仔细想想就连当年我第一个接触的红旗Linux也不过坚持了一个月,呵呵,又写了一段废话── 所 谓的“重回Kununtu” ...
- CodeForces 10C. Digital Root
乞讨A.B.C ∈[1.N] && A*B != C,d(A*B) == d(C)组的数量. 首先要知道d(x) = (x%9 == 0 ? 9 : x%9); 那么则会有A*B == ...
- 区域及分离、Js压缩、css、jquery扩展
后台管理区域及分离.Js压缩.css.jquery扩展 本系列目录:ASP.NET MVC4入门到精通系列目录汇总 有好一段时间没更新博文了,最近在忙两件事:1.看书,学习中...2.为公司年会节目做 ...
- CentOS7卸载KDE桌面(转)
最初安装centos时选择了安装KDE桌面,打开很卡,没有用到,想卸载,可是试了网上的方法什么yum groupremove kde-desktop 都不奏效,于是只能自己找出KDE的包,然后yum卸 ...
- Shell在大数据的魅力时代:从一点点思路百度大数据面试题
供Linux开发中的同学们,Shell这可以说是一个基本功. 对于同学们的操作和维护.Shell也可以说是一种必要的技能,Shell.对于Release Team,软件配置管理的同学来说.Shell也 ...
- UVALive 5103 Computer Virus on Planet Pandora Description 一些新兴需求模式的字符串 AC自己主动机
主题链接:option=com_onlinejudge&Itemid=8&page=show_problem&problem=3104">点击打开链接 题意: ...
- net搭建热插拔式web框架(沙箱的构建)
net搭建热插拔式web框架(沙箱的构建) 上周五写了一个实现原理篇,在评论中看到有朋友也遇到了我的问题,真的是有种他乡遇知己的感觉,整个系列我一定会坚持写完,并在最后把代码开源到git中.上一篇文章 ...