配色: 字号:
Android中AsyncTask分析--你所不注意的坑
2016-11-14 | 阅:  转:  |  分享 
  
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进行后续处理。

献花(0)
+1
(本文系thedust79首藏)