Android AsyncTask运作原理和源码分析
来源:互联网 发布:github for mac 教程 编辑:程序博客网 时间:2024/04/27 16:37
Android AsyncTask运作原理和源码分析
本文转自:http://www.cnblogs.com/answer1991/archive/2012/04/17/2454073.html 在此感谢原作者的辛勤贡献分享。拿来学习之
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 AsyncTask运作原理和源码分析
- Android AsyncTask运作原理和源码分析
- Android AsyncTask运作原理和源码分析
- Android AsyncTask原理-源码层分析
- [Android]--AsyncTask用法和源码分析
- Android AsyncTask原理分析
- Android AsyncTask源码分析
- Android源码分析--AsyncTask
- 源码分析Android AsyncTask
- Android AsyncTask源码分析
- Android-AsyncTask源码分析
- Android AsyncTask 源码分析
- android-----AsyncTask源码分析
- Android AsyncTask源码分析
- Android AsyncTask源码分析
- Android源码分析-AsyncTask
- 【Android】 AsyncTask 源码分析
- twisted异步机制-Deferred
- Qcom流程8x12
- Android 4.3 emulator screen stay black and qemu: could not load initrd 'ramdisk.img'
- Apache VirtualHost配置
- spring集成TestNg测试
- Android AsyncTask运作原理和源码分析
- Java中关键字static,final的理解
- java 二分查找
- 准备搬家了
- C++:STL标准入门汇总
- 考试笔记02_操作系统_换页算法
- 多视图
- Ubuntu 解压缩zip文件乱码问题解决方案
- mxd连接ArcSDE的几种方式