Android AsyncTask运作原理和源码分析
自10年大量看源码后,很少看了,抽时间把最新的源码看看!
public abstract class AsyncTask<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTask";
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 10;
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
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 ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static final int MESSAGE_POST_CANCEL = 0x3;
private static final InternalHandler sHandler = new InternalHandler();
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
private volatile Status mStatus = Status.PENDING;
/**
* Indicates the current status of the task. Each status will be set only once
* during the lifetime of a task.
*/
public enum Status {
/**
* Indicates that the task has not been executed yet.
*/
PENDING,
/**
* Indicates that the task is running.
*/
RUNNING,
/**
* Indicates that {@link AsyncTask#onPostExecute} has finished.
*/
FINISHED,
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return doInBackground(mParams);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
Message message;
Result result = null;
try {
result = 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) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
}
/**
* Returns the current status of this task.
*
* @return The current status.
*/
public final Status getStatus() {
return mStatus;
}
protected abstract Result doInBackground(Params... params);
protected void onPreExecute() {
}
@SuppressWarnings({"UnusedDeclaration"})
protected void onPostExecute(Result result) {
}
@SuppressWarnings({"UnusedDeclaration"})
protected void onProgressUpdate(Progress... values) {
}
protected void onCancelled() {
}
public final boolean isCancelled() {
return mFuture.isCancelled();
}
public final boolean cancel(boolean mayInterruptIfRunning) {
return mFuture.cancel(mayInterruptIfRunning);
}
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get();
}
public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
return mFuture.get(timeout, unit);
}
public final AsyncTask<Params, Progress, Result> execute(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;
sExecutor.execute(mFuture);
return this;
}
protected final void publishProgress(Progress... values) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
private void finish(Result result) {
onPostExecute(result);
mStatus = Status.FINISHED;
}
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;
case MESSAGE_POST_CANCEL:
result.mTask.onCancelled();
break;
}
}
}
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
}
以上是AsyncTask的全部代码。
-----------------------------------------------------------------
AsyncTask多用于Android的Context(Activity)处理后台逻辑同时又要兼顾主线程的一些逻辑(比如说Activity的UI更新)。
AsyncTask它其实是封装了一个多线程、向开发者屏蔽了考虑多线程的问题。开发人员只需去重写AsyncTask中的doInBackground、onProgressUpdate、onPreExecute、onPostExecute等方法,然后生成该对象并执行execute方法即可实现异步操作。
由于Android负责Context(Activity)的主线程(或者说是UI控制线程)不是线程安全的,也就是说开发者不能在自己生成的线程对象里面操作Activity的UI更新。
对于习惯了Java开发的开发人员来说,非要自己生成线程对象,在这个线程里操作一些时间较长的逻辑(比如下载文件),完成之后再提醒用户下载完成(UI更新,比如在一个TextView中把文字修改成"下载完成")的话,那么UI更新的工作只能借助于Handler(这个Handler必须是在主线程中生成,或者说和主线程共用一个Looper和MessageQueue,通常的方法是在Activity中的onCreate方法中生成重写的Handler对象)。当开发者的线程完成逻辑操作之后,发送一个消息到Handler,再由Handler去处理。如果Handler由主线程生成,那么这个Handler的handleMessage()会在主线程中执行,因此在handleMessage()中可以访问Activity中的某个View并修改。如一下代码:
public class TestActivity extends Activity{
private static final int WHAT = 0x01;<br>
private Thread downloadThread;
private Handler refleshHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.main);
super.onCreate(savedInstanceState);
downloadThread = new Thread(new DownloadRunnable());
refleshHandler = new RefleshHandler();
downloadThread.start();
}
private class DownloadRunnable implements Runnable {
public void run() {
System.out.println("开始处理业务");
//耗时较长的逻辑代码省略
refleshHandler.sendEmptyMessage(WHAT);
}
}
private class RefleshHanler extends Handler{
@Override
public void handleMessage(Message msg) {
if(msg.what == WHAT){
//更新TestActivity UI
}
}
}
上述的方法也未尝不是一种好的方法。然而Android为开发者提供了一种新的解决方案,那就是AsyncTask,分析完源代码会发现,其实AsyncTask为我们封装了上述的方法。
对于我们重写AsyncTask的doInBackground()的方法,AsyncTask会将它封装成一个实现Callable接口的对象,在线程池中找出一个线程是实现它,因此我们所需要的耗时较长的逻辑可以放在这个方法里面。
AsyncTask也维护着一个静态的Handler,这个Handler属于创建AsyncTask的线程,而创建AsyncTask一般都是主线程(UI线程),因此这个Handler可以访问并Activity的UI。
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;
case MESSAGE_POST_CANCEL:
result.mTask.onCancelled();
break;
}
}
}
可以看到这个Handler操作了AsyncTask的三个方法:finish() , onProgressUpdate() , onCancelled(),而finish() 又调用onPostExecute()方法。
可以这么说,onProgressUpdate() ,onCancelled(),onPostExecute() 用来被开发者重写,去更新UI的,这3个方法会涉及到UI的操作,因此doInBackground()方法里不能调用这几个方法,也就是说开发者可以重写这些方法,但是又不能直接调用这些方法,只能通过发送消息给Handler的方式来隐式的调用。
onProgressUpdate()是一个更新处理进度的方法,开发者可以重写它,可以将它关联到Activity的一个进度条控件上,在doInBackground()里可以用publishProgress()去间接调用它(其实这个函数也是通过发送what为MESSAGE_POST_PROGRESS的Message给Handler的方式来调用onProgressUpdate()的),这样就能在UI上显示进度信息。
finish()方法,也就是onPostExecute(),是处理完doInBackground()得到结果之后的调用。doInBackground()的函数封装在实现Callable接口的名叫一个WorkerRunnable的抽象类中,再将这个类封装在Future中,并重写Future的done()方法,这个方法会在Callable的call方法执行完之后调用,就是doInBackground()方法执行完之后调用,它可以获得执行完的结果,Future.get()方法(可能阻塞),并将得到的结果封装在what为MESSAGE_POST_RESULT的Message中,并发送。上诉的核心代码如下:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return doInBackground(mParams);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
Message message;
Result result = null;
try {
result = 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) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
同理,onCancelled()是在AsyncTask被取消时的调用,也是通过Handler的方法。
有一点要注意到,还有一个onPreExecute()方法,虽然这个方法是未被Handler加入到消息处理的方法里,但是这个方法是在execute()里执行的,execute是主线程(UI线程)才会去执行的,所以这个方法也能访问和修改UI。
总结: 开发者可以重写AsyncTask的onProgressUpdate() , onCancelled(), onPostExecute(), onPreExecute(), doInBackground()方法,以得到异步实现后台逻辑并更新UI的操作。
其中onProgressUpdate() , onCancelled(), onPostExecute(), onPreExecute() 可以直接访问并修改UI。
但是doInBackground()不能出现涉及UI的操作,也不能直接调用onProgressUpdate() , onCancelled(), onPostExecute(), onPreExecute() 这四个方法,后三者不需要调用,可以通过publishProgress()去间接的调用onProgressUpdate()方法。
最后要说的是AsyncTask的对象一旦生成之后,execute()方法只能被调用一次,即使是同样的操作,也需要重新生成AsyncTask对象才行。
Android AsyncTask运作原理和源码分析的更多相关文章
- Android Debuggerd 简要介绍和源码分析(转载)
转载: http://dylangao.com/2014/05/16/android-debuggerd-%E7%AE%80%E8%A6%81%E4%BB%8B%E7%BB%8D%E5%92%8C%E ...
- Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析
相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...
- Kubernetes Job Controller 原理和源码分析(一)
概述什么是 JobJob 入门示例Job 的 specPod Template并发问题其他属性 概述 Job 是主要的 Kubernetes 原生 Workload 资源之一,是在 Kubernete ...
- Kubernetes Job Controller 原理和源码分析(二)
概述程序入口Job controller 的创建Controller 对象NewController()podControlEventHandlerJob AddFunc DeleteFuncJob ...
- Kubernetes Job Controller 原理和源码分析(三)
概述Job controller 的启动processNextWorkItem()核心调谐逻辑入口 - syncJob()Pod 数量管理 - manageJob()小结 概述 源码版本:kubern ...
- Android IntentService的使用和源码分析
引言 Service服务是Android四大组件之一,在Android中有着举足重轻的作用.Service服务是工作的UI线程中,当你的应用需要下载一个文件或者播放音乐等长期处于后台工作而有没有UI界 ...
- Java1.7 HashMap 实现原理和源码分析
HashMap 源码分析是面试中常考的一项,下面一篇文章讲得很好,特地转载过来. 本文转自:https://www.cnblogs.com/chengxiao/p/6059914.html 参考博客: ...
- 深入ReentrantLock的实现原理和源码分析
ReentrantLock是Java并发包中提供的一个可重入的互斥锁.ReentrantLock和synchronized在基本用法,行为语义上都是类似的,同样都具有可重入性.只不过相比原生的Sync ...
- ☕【Java深层系列】「并发编程系列」让我们一起探索一下CyclicBarrier的技术原理和源码分析
CyclicBarrier和CountDownLatch CyclicBarrier和CountDownLatch 都位于java.util.concurrent这个包下,其工作原理的核心要点: Cy ...
随机推荐
- Unity3d 调用C++的DLL
原地址:http://www.cnblogs.com/alongu3d/archive/2013/04/20/3031904.html Unity 3D 调用DLL的方法 本文转载:渡蓝的博客园 ht ...
- UVALive 5903 Piece it together
一开始用的STL一直超时不能过,后来发现AC的代码基本都用的普通邻接表,然后改了一下13s,T=T,效率太低了.然后把某大神,详情戳链接http://acm.hust.edu.cn/vjudge/pr ...
- H2O与Java线程同步
Java 5以前的线程同步采用syncronized和wait,notify,notifyAll来实现,比较粗糙.之后有了Lock和Condition.ReentrantLock的简单lock,unl ...
- 关于fastclick.js
Fastclick fastclick.js解决了什么问题? 自己接触WebApp开发的前期, 总感觉WebApp上的按键操作不如NativeApp的灵敏, 好像有那么一小点延迟. 后来才知道, 这是 ...
- Reflector+Reflexil 相结合实现对DLL文件修改
在工作过程中,我们有可能遇到这样的问题:公司发给客户的软件包突然报错了,但是你知道哪里报错了,而这个代码已经编译成DLL文件了,源代码不在自己这里.怎么办呢?还好现在有Reflexil插件,这个插件只 ...
- 六月计划#1A(6.1-6.8)
5/35 数学 BZOJ_[HNOI2008]_Cards_(置换+Burnside引理+乘法逆元+费马小定理+快速幂) BZOJ_1005_ [HNOI2008]_明明的烦恼_(组合数学+purfe ...
- 一个不错的php图片处理类EasyPhpThumbnail Class
EasyPhpThumbnail Class EasyPhpThumbnail Class用于处理图片操作和生成缩略图.支持GIF.JPG和PNG三种格式. 提供的功能包括:Resize.剪切.旋 ...
- 自动测试框架(by myself)
这段日子以来一直在自动话测试,然后关于框架一直有个很模糊的概念,通过N多人的解说,这个应该不能算是一个框架,但是还是很模糊 如下图是我自己认为的框架,不知道是否正确(请大侠们多多指点) 1.用nuni ...
- debian下安装AMD驱动
参考:http://blog.sciencenet.cn/blog-296919-464464.html 去AMD官网下载对应的驱动: amd-driver-installer-catalyst-13 ...
- HDOJ-ACM1425 sort 简单hash应用
其实快排也可以通过这个问题~不是考点 没想到考点是这个,简单hash应用,空间换时间 初始化一个长度为1000001的数组(由于数字的范围为[-500000,500000]) 如果存在这个数m,数组下 ...