Android中AsyncTask分析--你所不注意的坑
AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
本文不分析AsyncTask的使用,它的使用教程网上一搜一大堆,本文主要分析它的内部逻辑和实现,它是怎么实现异步的,它是怎么处理多个任务的,是并发么??
一、线程任务的调度
在AsyncTask内部会创建一个类相关的线程池来管理要运行的任务,也就就是说当你调用了AsyncTask的execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Therad。
在Android4.0版本中它内部是有两个线程池:SerialExecutor和ThreadPoolExecutor,SerialExecutor是串行的,ThreadPoolExecutor是并发的,而默认的就是SerialExecutor的,所以你一个程序中如果用了好几个AsyncTask你就得注意了:不要忘了换成并发的线程池执行。下面演示一下,穿行的调度
1.一个简单的例子:可以看出他是一个个执行的
代码如下:
publicclassAsyncTaskDemoActivityextendsActivity{
privatestaticintID=0;
privatestaticfinalintTASK_COUNT=9;
privatestaticExecutorServiceSINGLE_TASK_EXECUTOR;
privatestaticExecutorServiceLIMITED_TASK_EXECUTOR;
privatestaticExecutorServiceFULL_TASK_EXECUTOR;
static{
SINGLE_TASK_EXECUTOR=(ExecutorService)Executors.newSingleThreadExecutor();
LIMITED_TASK_EXECUTOR=(ExecutorService)Executors.newFixedThreadPool(7);
FULL_TASK_EXECUTOR=(ExecutorService)Executors.newCachedThreadPool();
};
@Override
publicvoidonCreate(Bundleicicle){
super.onCreate(icicle);
setContentView(R.layout.asynctask_demo_activity);
Stringtitle="AsyncTaskofAPI"+VERSION.SDK_INT;
setTitle(title);
finalListViewtaskList=(ListView)findViewById(R.id.task_list);
taskList.setAdapter(newAsyncTaskAdapter(getApplication(),TASK_COUNT));
}
privateclassAsyncTaskAdapterextendsBaseAdapter{
privateContextmContext;
privateLayoutInflatermFactory;
privateintmTaskCount;
ListmTaskList;
publicAsyncTaskAdapter(Contextcontext,inttaskCount){
mContext=context;
mFactory=LayoutInflater.from(mContext);
mTaskCount=taskCount;
mTaskList=newArrayList(taskCount);
}
@Override
publicintgetCount(){
returnmTaskCount;
}
@Override
publicObjectgetItem(intposition){
returnmTaskList.get(position);
}
@Override
publiclonggetItemId(intposition){
returnposition;
}
@Override
publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
if(convertView==null){
convertView=mFactory.inflate(R.layout.asynctask_demo_item,null);
SimpleAsyncTasktask=newSimpleAsyncTask((TaskItem)convertView);
/
Itonlysupportsfivetasksatmost.Moretaskswillbescheduledonlyafter
firstfivefinish.Inall,thepoolsizeofAsyncTaskis5,atanytimeitonly
has5threadsrunning.
/
task.execute();
//useAsyncTask#SERIAL_EXECUTORisthesameto#execute();
//task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
//useAsyncTask#THREAD_POOL_EXECUTORisthesametoolderversion#execute()(lessthanAPI11)
//butdifferentfromnewerversionof#execute()
//task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
//onebyone,sametonewerversionof#execute()
//task.executeOnExecutor(SINGLE_TASK_EXECUTOR);
//executetasksatsomelimitwhichcanbecustomized
//task.executeOnExecutorwww.baiyuewang.net(LIMITED_TASK_EXECUTOR);
//nolimittothreadpoolsize,alltasksrunsimultaneously
//task.executeOnExecutor(FULL_TASK_EXECUTOR);
mTaskList.add(task);
}
returnconvertView;
}
}
privateclassSimpleAsyncTaskextendsAsyncTask{
privateTaskItemmTaskItem;
privateStringmName;
publicSimpleAsyncTask(TaskItemitem){
mTaskItem=item;
mName="Task#"+String.valueOf(++ID);
}
@Override
protectedVoiddoInBackground(Void...params){
intprog=1;
while(prog<101){
SystemClock.sleep(100);
publishProgress(prog);
prog++;
}
returnnull;
}
@Override
protectedvoidonPostExecute(Voidresult){
}
@Override
protectedvoidonPreExecute(){
mTaskItem.setTitle(mName);
}
@Override
protectedvoidonProgressUpdate(Integer...values){
mTaskItem.setProgress(values[0]);
}
}
}
classTaskItemextendsLinearLayout{
privateTextViewmTitle;
privateProgressBarmProgress;
publicTaskItem(Contextcontext,AttributeSetattrs){
super(context,attrs);
}
publicTaskItem(Contextcontext){
super(context);
}
publicvoidsetTitle(Stringtitle){
if(mTitle==null){
mTitle=(TextView)findViewById(R.id.task_name);
}
mTitle.setText(title);
}
publicvoidsetProgress(intprog){
if(mProgress==null){
mProgress=(ProgressBar)findViewById(R.id.task_progress);
}
mProgress.setProgress(prog);
}
}
2.你想要的并发执行
上面的情况肯定不是你想要的,你想要的应该是这种情况:
只需要修改一行代码:
1
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
当然也可以换成你自己的线程池。
二、源码分析
1.成员变量:
定义了需要用到的成员,可以根据名字就能知道干什么的
//生产线程的工厂
privatestaticfinalThreadFactorysThreadFactory=newThreadFactory(){
privatefinalAtomicIntegermCount=newAtomicInteger(1);
publicThreadnewThread(Runnabler){
returnnewThread(r,"AsyncTask#"+mCount.getAndIncrement());
}
};
//存放任务的阻塞队列
privatestaticfinalBlockingQueuesPoolWorkQueue=
newLinkedBlockingQueue(10);
/
可以平行的执行任务!就是并发的
An{@linkExecutor}thatcanbeusedtoexecutetasksinparallel.
/
publicstaticfinalExecutorTHREAD_POOL_EXECUTOR
=newThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE,
TimeUnit.SECONDS,sPoolWorkQueue,sThreadFactory);
/
线性执行的执行器
An{@linkExecutor}thatexecutestasksoneatatimeinserial
order.Thisserializationisglobaltoaparticularprocess.
/
publicstaticfinalExecutorSERIAL_EXECUTOR=newSerialExecutor();
//内部交互的handler
privatestaticfinalInternalHandlersHandler=newInternalHandler();
//默认的Executor
privatestaticvolatileExecutorsDefaultExecutor=SERIAL_EXECUTOR;
定义了需要用到的成员,可以根据名字就能知道干什么的,另外注意都是static修饰的:
第二行的sThreadFactory是创建线程的;
第十行的sPoolWorkQueue阻塞队列,存放任务的;
第十七行是THREAD_POOL_EXECUTOR是线程池,这个是并发执行的线程池;
第26行是线性调度的线程池,SERIAL_EXECUTOR,执行完一个才会执行下一个;
第28行是一个内部封装的Handler:InternalHandler
第30行可以看出他默认的是线性调度的线程池,ExecutorsDefaultExecutor=SERIAL_EXECUTOR,看到这里你应该注意一个问题,如果程序里有好多个AsyncTask,它们就是线性调度的,这肯定可你预想的不一样,所以你别忘了换成并发的执行器。
2.内部Handler的使用:
2.1自定义的InternalHandler(内部handler)
privatestaticclassInternalHandlerextendsHandler{
@SuppressWarnings({"unchecked","RawUseOfParameterizedType"})
@Override
//接受message的处理,可以看到根据状态选择是完成了,还是更新着
publicvoidhandleMessage(Messagemsg){
AsyncTaskResultresult=(AsyncTaskResult)msg.obj;
switch(msg.what){
caseMESSAGE_POST_RESULT:
//Thereisonlyoneresult
result.mTask.finish(result.mData[0]);
break;
caseMESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
在上边handleMessage中,根据msg进行判断,是完成了还是在更新;
任务完成调用finish方法,在其中执行你定义的onPostExecute方法,
privatevoidfinish(Resultresult){
if(isCancelled()){
onCancelled(result);
}else{
onPostExecute(result);
}
mStatus=Status.FINISHED;
}
3.构造方法
publicAsyncTask(){
mWorker=newWorkerRunnable(){
publicResultcall()throwsException{
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
returnpostResult(doInBackground(mParams));
}
};
mFuture=newFutureTask(mWorker){
@Override
protectedvoiddone(){
try{
finalResultresult=get();
postResultIfNotInvoked(result);
}catch(InterruptedExceptione){
android.util.Log.w(LOG_TAG,e);
}catch(ExecutionExceptione){
thrownewRuntimeException("AnerroroccuredwhileexecutingdoInBackground()",
e.getCause());
}catch(CancellationExceptione){
postResultIfNotInvoked(null);
}catch(Throwablet){
thrownewRuntimeException("Anerroroccuredwhileexecuting"
+"doInBackground()",t);
}
}
};
}
构造方法中其实隐藏的信息很多,WorkerRunnable和FutureTask;
其中WorkerRunnable继承了Callable接口,应该是用于在未来某个线程的回调接口,在其中执行了ostResult(doInBackground(mParams));调用doInBackground并用postResult方法,把result发送到主线程。
FutureTask你看类的介绍是说控制任务的,控制任务的开始、取消等等,在这不细究,跟本文关系不大,而且我也没看明白。
第17行有一个方法:postResultIfNotInvoked(result);根据名字可以看出来是如果没有调用把把结果post出去,所以他应该是处理取消的任务的。
构造方法就分析到这,下一步就是execute():
看下postResult方法:代码很少也很简单,就是把msg发送给handler:
//用shandler把设置message,并发送。
privateResultpostResult(Resultresult){
Messagemessage=sHandler.obtainMessage(MESSAGE_POST_RESULT,
newAsyncTaskResult(this,result));
message.sendToTarget();
returnresult;
}
3.1按照执行过程流程,实例化完,就可以调用execute():
//Params...就相当于一个数组,是传给doInBackground的参数
publicfinalAsyncTaskexecute(Params...params){
returnexecuteOnExecutor(sDefaultExecutor,params);
}
//执行逻辑
publicfinalAsyncTaskexecuteOnExecutor(Executorexec,
Params...params){
if(mStatus!=Status.PENDING){
switch(mStatus){
caseRUNNING:
thrownewIllegalStateException("Cannotexecutetask:"
+"thetaskisalreadyrunning.");
caseFINISHED:
thrownewIllegalStateException("Cannotexecutetask:"
+"thetaskhasalreadybeenexecuted"
+"(ataskcanbeexecutedonlyonce)");
}
}
//改变状态
mStatus=Status.RUNNING;
//准备工作
onPreExecute();
mWorker.mParams=params;
exec.execute(mFuture);
returnthis;
}
代码逻辑很清晰,没有几行:
20行:修改了状态;
21行:准备工作;
24行:设置参数;
25行:线程池调用执行,注意参数是mFuture。
3.2execute的执行逻辑
就以它定义SerialExecutor为例:
/An{@linkExecutor}thatexecutestasksoneatatimeinserial
order.Thisserializationisglobaltoaparticularprocess./
privatestaticclassSerialwww.wang027.comExecutorimplementsExecutor{
finalArrayDequemTasks=newArrayDeque();
RunnablemActive;
publicsynchronizedvoidexecute(finalRunnabler){
mTasks.offer(newRunnable(){
publicvoidrun(){
try{
r.run();
}finally{
scheduleNext();
}
}
});
if(mActive==null){
scheduleNext();
}
}
protectedsynchronizedvoidscheduleNext(){
if((mActive=mTasks.poll())!=null){
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
可以看到它的方法都是用synchronized关键字修饰的,而其让他的介绍里也说了在同一时间只有一个任务在执行。
在里边调用r.run()方法,执行完了在调用下一个。按先后顺序每次只运行一个
三、AsyncTask中异步的处理逻辑
没有忘了前边构造方法中的postResult(doInBackground(mParams))和postResultIfNotInvoked(result);方法吧,如果忘了翻前边去看。这两个方法把执行成功的和失败的任务都包含了。
所以我们可以设想一下它是怎么执行的:
1.在executeOnExecutor方法中给变量赋值
2.用执行器Executor另起线程执行任务
3.在Executor中一些复杂的逻辑,用FutureTask进行判断任务是否被取消,如果没有就调用回调接口call()方法,
4.在call()方法中调用了postResult(doInBackground(mParams));
5.postResult发送给主线程的Handler进行后续处理。
|
|