You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
调用AsyncTask的execute方法会调用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;
}
前言
AsyncTask
、HandlerThrad
、IntentService
都是对Android消息机制的封装和应用,解决在子线程耗时任务,主线程更新UI的问题。AsyncTask的使用
AsyncTask是一个抽象类,通过子类继承重写
doInBackground
,该方法在子线程运行。AsyncTask<Params, Progress, Result>
的泛型参数,可以根据业务需求,传不同的类型。第一个参数Params
是指传到doInBackground
的参数类型,例如瞎子啊进度的URL。第二个参数Progress
是指在执行doInBackground
方法时,通过publishProgress
更新进度状态的类型,例如下载的进度。第三个参数Result
是doInBackground
方法执行结束后传到onPostExecute
的参数类型,例如下载结果。相关方法
运行在主线程。可以开始任务之前,对UI或者数据进行初步准备。非必需方法。
在子线程(线程池)运行。一般进行耗时操作,例如下载。为AsyncTask的抽象方法,必须实现。
运行在主线程,在doInBackground方法中调用publishProgress方法会回调该方法,显示当前任务状态。常用来更新下载进度。非必需方法。
在主线程运行。在doInBackground方法中return值之后,将回调该方法。非必需方法。
在主线程运行,任务完成时回调该方法,表示任务结束。
开始任务
task的execute只能调用一次,不然报错。
源码分析
AsyncTask的构造函数
Android中代码注释是必须在UI线程中调用,因为UI线程默认拥有Looper,以及AsyncTask需要更新UI。如果不需要更新UI,在有Looper的子线程都可以创建。
构造方法1、2,最终调用构造方法3。看看构造方法3做了什么?
分析一
给mHanlder赋值初始化。先判断是否传入Looper对象,如果没有传入,或者传入Looper对象并且和UI线程的Looper相同,则通过调用
getMainHandler
方法调用UI线程的Handler对象(这里可以简单理解,AsyncTask在UI线程创建的)。如果不相等,new
一个Handler
对象。AsyncTask的
getMainHandler
方法,通过调用Looper的getMainLooper
方法来获得Looper对象(UI线程的Looper对象)并创建InternalHandler。这里可以看到,在没有传入Looper的情况,且不在UI线程创建AsyncTask,会获取不到Looper对象。sHandler变量是InternalHandler类型,继承Handler。在方法处理中,可以看到是对
MESSAGE_POST_RESULT
消息和MESSAGE_POST_PROGRESS
消息的处理,用来在任务结束和进度更新时,切换到主线程,回调相关方法。分析二
静态抽象类WorkerRunnable继承Callable,只多添加了数组mParams,用于保存参数。在WorkerRunnable的
call
方法中,主要调用我们重写的doInBackground
。最终对调用postResult
方法。在分析一中,最后看到InternalHandler对象对MESSAGE_POST_RESULT消息的处理,调用AsyncTask对象的
finish
方法。根据当前AsyncTask的状态调用
onCancelled
或者onPostExecute
方法。在AsyncTask的构造方法中。通过构造Handler对象,和构造WorkRunnable对象,并将WorkRunnable对象用于创建FutureTask对象。FutureTask实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable接口和Future接口。所以FutureTask既能做一个Runnable对象直接被Thread执行,也能作为Future对象用来得到Callable的计算结果。
AsyncTask的执行
我们在UI线程创建DownloadTask对象,并将调用DownloadTask对象的
execute
方法,Git
方法是我们要传到doInBackground
方法的值;调用AsyncTask的
execute方
法会调用executeOnExecutor
方法。如果当前AsyncTask对象正在运行或者结束,会抛出异常,一个task只能运行一次。在这里调用了
onPreExecute
方法,并参数赋值给了前面讲到的WorkerRunable对象的omParams变量。通过线程池对象exex执行在构造方法创建的FutureTask对象,最终对调用WorkerRunable对象的call
方法,从而执行我们重写的doInBackground
方法。这里我们看看线程池对象sDefaultExecutor。
类SerialExecutor的构造方法
通过ArrayDequ保存任务,并以加锁机制同步execute方法,串行执行任务。
THREAD_POOL_EXECUTO
是什么东东?毫无意外是一个线程池。
总结
通过AsyncTask的构造器的跟踪,我们了解AsyncTask的实现的整体流程。通过Looper对象创建Handler对象,用于在线程池中发送消息,切换到UI线程,进行相关操作。并创建WorkRunnable对象调用后台任务(我们重写的
doInBackground
方法),将WorkRunnable对象传给FutureTask对象,这样在线程池中执行时,对结果和过程可控。在AsyncTask的
execute
方法追踪,我们知道后台任务采用双向队列保存,线程池通过锁同步串行运行。另外需要注意的是,AsyncTask的生命周期和Activity的生命周期并不一致,若AsyncTask持有Activity,容易造成内存泄漏。类似下载耗时操作建议采用
IntentServcie
。The text was updated successfully, but these errors were encountered: