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的源码目录例如 ...
随机推荐
- yum 简介及使用 安装、删除
使用yum装软件很方便,这里简单介绍一下. Yum简介 Yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE.CentOS中的She ...
- POJ 2250 Compromise (UVA 531)
LCS问题.基金会DP. 我很伤心WA非常多.就在LCS问题,需要记录什么路. 反正自己的纪录path错误,最后,就容易上当. 没有优化,二维阵列,递归打印,cin.eof() 来识别 end of ...
- 使用clojure訪问SQL Server数据库
(require '[korma.core :as kc]) (require '[korma.db :as kd]) (Class/forName "com.microsoft.jdbc. ...
- css--左右visibility建立 “collapse”值问题
1.您可能已使用visibility一千次,最常用的是visible和hidden.它用来显示或隐藏元素. 有第三很少已使用的值它是collapse,在表格的行,列中使用有差异外,他和hidden的作 ...
- Windows Phone 的控件倾斜效果
原文:Windows Phone 的控件倾斜效果 Windows Phone 7的系统设置里,按钮都有一个点击倾斜的效果,但自己添加的控件就没有.但微软提供了这个效果的代码:TiltEffect MS ...
- java设计模式演示示例
创建一个模式 1.工厂方法模式(Factory Method) 该程序创建的操作对象,独自一人走出流程,创建产品工厂接口.实际的工作转移到详细的子类.大大提高了系统扩展的柔性,接口的抽象化处理给相互 ...
- 在AcGIS随着大数据的生成DEM
在ArcGIS产生DEM时间.数据来源是经常有的高程点.轮廓线,该高程点.等高线密集,可能有几千万.甚至亿高程点.轮廓线. 如果您使用这些矢量数据生成TIN.不能实现的,由于生成TIN时,支持的最大结 ...
- [Unity3D]Unity3D游戏开发《反对》说到游戏(上)——目标跟踪
朋友,大家好.我是秦培,欢迎关注我的博客.我的博客地址blog.csdn.net/qinyuanpei. 首先博主要自我反省,过了这么久才来更新博客,这段时间主要是在忙着写期末的作业,所以博主基本上没 ...
- [cocos2dx注意事项014]一个用于cocos2dx对象智能指针模板
现在,C++有许多实现智能指针,一个更无所谓.哈. 这种智能指针是专为cocos2dx 2.2.x自定义.主要的易用性,同时必须遵循现有的cocos2dx内存管理.特殊实现这样的智能指针.无需在使用时 ...
- Android官方技术文档翻译——Gradle 插件用户指南(1-3)
不知道是什么网络问题,上午一直发不了博客,其它页面基本正常,就是在写博客这里,每次打开都是响应超时.刚才用了VPN,顺便试了一下,竟然能够编辑.想是CDN之类的问题吧. 这次翻译的是Gradle 插件 ...