Android在框架层提供了异步任务类,AysncTask,用于执行后台任务,并将执行结果更新到UI线程。为什么要用异步任务呢?这是因为如果某个任务太耗时间的话,会阻塞UI主线程,而我们知道UI线程如果阻塞5秒的话,就会发生ANR(Application No Response)错误 ,就算没有发生,主界面上看起来也会卡卡的,这显然用户体验就不太好了。

而AsyncTask类则在不影响UI线程的情况下,另起子线程去做那些耗时比较久的任务,比如我们在TodoList中去读取图片这种情况,然后将处理后的结果再更新到UI线程,从而达到更好的用户体验。

下面是AsyncTask类的定义:

[java] view plain copy
  1. publicabstractclassAsyncTask<Params,Progress,Result>{
  2. privatestaticfinalStringLOG_TAG="AsyncTask";
  3. ...

从上面的代码可以看出,AsyncTask是一个抽象类,所以在使用AsyncTask的时候,我们要继承它,实现一个子类,并实现其中一个方法,如下:

[java] view plain copy
  1. classLoadImageTaskextendsAsyncTask<String,Void,ImageView>{
  2. @Override
  3. protectedImageViewdoInBackground(String...params){
  4. StringphotoImagePath=params[0];
  5. Bitmapbitmap=BitmapReader.readBigBitmapFromFile(photoImagePath,REQ_WIDTH);
  6. ImageViewimageView=Helper.createImageViewFromBitmap(DetailActivity.this,bitmap);
  7. returnimageView;
  8. }
  9. protectedvoidonPostExecute(ImageViewresult){
  10. imageViews.add(result);
  11. refreshGallery();
  12. }
  13. }

对照 AsyncTask的三个参数,Params, Progress和Result,是泛型参数。

1)Params :参数,比如例子中定义的String类型,指向一个Image的路径,这是传给AysncTask的doInBackground方法。

2)Progress:这是在执行过程中会用到的一个参数,一般在显示进度的时候会用到,在例子中不会用到,所以可以在这里指定为Void。

3)Result:这是执行的结果对象,会作为onPostExecute方法的参数,在UI线程中处理。

由上面的例子也可以看到,一般我们实现的这个子类,要实现其中的两个方法

1)doInBackground:这个方法,其实是在另外一个线程中执行的。

2)onPostExecute:而这个方法却已经回到UI线程中来执行,所以可以在这里将上一个方法中执行所得的结果在这里更新到UI线程中。

那么这里面的机制是怎么样的呢,我们就来深入地看一下,也学习一下吧。

首先我们来看一下在Activity中,我们是怎么样来使用我们这个AsyncTask的吧,代码如下:

[java] view plain copy
  1. @Override
  2. protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
  3. if(requestCode==REQUEST_FOR_CAMERA){
  4. if(resultCode==RESULT_OK){
  5. isPhotoTaken=true;
  6. photoFileNames.add(tempPhotoFileName);
  7. }
  8. }elseif(requestCode==REQUEST_FOR_GALLERY){
  9. if(resultCode==RESULT_OK){
  10. isPhotoTaken=true;
  11. ContentResolverresolver=getContentResolver();
  12. Uriuri=data.getData();
  13. tempPhotoFileName=Helper.getImagePath(resolver,uri);
  14. photoFileNames.add(tempPhotoFileName);
  15. }
  16. }
  17. newLoadImageTask().execute(tempPhotoFileName);//调用其execute方法
  18. }
在TodoList的小demo中,在相机或者图库返回来图片的路径之后,我们就会调用AsynctTask的execute方法了,那么这里就是入口了。

进入AsyncTask类中,找到execute方法,如下:

[java] view plain copy
  1. publicfinalAsyncTask<Params,Progress,Result>execute(Params...params){
  2. returnexecuteOnExecutor(sDefaultExecutor,params);
  3. }
可以看到,这里调用的是executeOnExecutor方法,我们继续找: [java] view plain copy
  1. publicfinalAsyncTask<Params,Progress,Result>executeOnExecutor(Executorexec,
  2. Params...params){
  3. if(mStatus!=Status.PENDING){
  4. switch(mStatus){
  5. caseRUNNING:
  6. thrownewIllegalStateException("Cannotexecutetask:"
  7. +"thetaskisalreadyrunning.");
  8. caseFINISHED:
  9. thrownewIllegalStateException("Cannotexecutetask:"
  10. +"thetaskhasalreadybeenexecuted"
  11. +"(ataskcanbeexecutedonlyonce)");
  12. }
  13. }
  14. mStatus=Status.RUNNING;
  15. onPreExecute();
  16. mWorker.mParams=params;
  17. exec.execute(mFuture);
  18. returnthis;
  19. }
在这个方法中,我们可以发现,AsynctTask定义了一个mStatus的成员变量,来表示异步任务的运行状态,分别是pending,running和finished,但只有处于pending状态的AsnycTask才能被执行。当状态是Pending的时候,就会继续执行,将状态变成running,这样能够保证AsyncTask只会被执行一次。

接着会调用onPreExecute方法做一些处理工作,这个方法其实我们也可以在子类中自己实现,如果有什么需要处理的话,一般不用。

然后我们发现,我们传进来的参数params会被传给mWorker,然后会有一个executor来执行execute的方法,并且执行的参数是一个mFuture对象。那么这两个东西是什么呢?

接着看如下代码:

[java] view plain copy
  1. publicAsyncTask(){
  2. mWorker=newWorkerRunnable<Params,Result>(){
  3. publicResultcall()throwsException{
  4. mTaskInvoked.set(true);
  5. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
  6. //noinspectionunchecked
  7. returnpostResult(doInBackground(mParams));
  8. }
  9. };
  10. mFuture=newFutureTask<Result>(mWorker){
  11. @Override
  12. protectedvoiddone(){
  13. try{
  14. postResultIfNotInvoked(get());
  15. }catch(InterruptedExceptione){
  16. android.util.Log.w(LOG_TAG,e);
  17. }catch(ExecutionExceptione){
  18. thrownewRuntimeException("AnerroroccuredwhileexecutingdoInBackground()",
  19. e.getCause());
  20. }catch(CancellationExceptione){
  21. postResultIfNotInvoked(null);
  22. }
  23. }
  24. };
  25. }

mWorker是一个WorkerRunnable对象,而实际上WorkerRunnable是AsyncTask的一个抽象内部类,实现了Callable接口,如下:

[java] view plain copy
  1. privatestaticabstractclassWorkerRunnable<Params,Result>implementsCallable<Result>{
  2. Params[]mParams;
  3. }
而在上面的赋值过程,通过匿名类实现了WorkerRunnable,并其call方法中将线程优先级调整为后台线程,然后会执行 doInBackground方法,不过现在还没执行,咱们再看看FutureTask对象,下面是它的构造函数: [java] view plain copy
  1. publicFutureTask(Callable<V>callable){
  2. if(callable==null)
  3. thrownewNullPointerException();
  4. sync=newSync(callable);
  5. }

而FutureTask是Java多线程模型的一部分,其间接地实现了Runnable(线程属性)接口和Future(异步任务)接口,而在上面的executeOnExecutor方法中,正是将mWorker(实现了Callable接口)对象传给它了,并被其封装到成员变量sync中,这样它们就共同表示了一个异步任务,到这里,一个异步任务也就创建完成了。

从上面executeOnExecutor的方法,也可以看到,真正执行execute是一个Executor,而在AsyncTask中,其实是SerialExecutor,我们看看其构造函数:

[java] view plain copy
  1. privatestaticclassSerialExecutorimplementsExecutor{
  2. finalArrayDeque<Runnable>mTasks=newArrayDeque<Runnable>();
  3. RunnablemActive;
  4. publicsynchronizedvoidexecute(finalRunnabler){
  5. mTasks.offer(newRunnable(){
  6. publicvoidrun(){
  7. try{
  8. r.run();//在新线程中调用了我们上面传进来的FutureTask的run方法
  9. }finally{
  10. scheduleNext();
  11. }
  12. }
  13. });
  14. if(mActive==null){
  15. scheduleNext();
  16. }
  17. }
  18. protectedsynchronizedvoidscheduleNext(){
  19. if((mActive=mTasks.poll())!=null){
  20. THREAD_POOL_EXECUTOR.execute(mActive);
  21. }
  22. }
  23. }

从上面,我们可以看到execute方法的参数就是一个Runnable,其实也就是FutrueTask了,在这里,它会被封装到一个新的线程中作为一个任务添加到mTasks队列中,至于下面如何在THREAD_POOL_EXECUTOR中去执行mTasks我们就不再深入下去了,我们就来看看FutureTask的run方法,如下:

[java] view plain copy
  1. publicvoidrun(){
  2. sync.innerRun();
  3. }
我们发现,它调用的是sync.innerRun(),那么Sync的innerRun方法又干了什么呢? [java] view plain copy
  1. voidinnerRun(){
  2. if(!compareAndSetState(READY,RUNNING))
  3. return;
  4. runner=Thread.currentThread();
  5. if(getState()==RUNNING){//recheckaftersettingthread
  6. Vresult;
  7. try{
  8. result=callable.call();
  9. }catch(Throwableex){
  10. setException(ex);
  11. return;
  12. }
  13. set(result);
  14. }else{
  15. releaseShared(0);//cancel
  16. }
  17. }
我们发现,它调用了callable的call方法,啊,我们终于来到了mWorker的call方法,回过头看,不就是在那里调用了doInBackground方法的吗?所以,我们可以确定,doInBackground的确是在一个新的线程中执行的,并且是一个后台线程。

但同时我们发现,其执行完之后,是作为一个参数传递给postResult的,继续看下去:

[java] view plain copy
  1. privateResultpostResult(Resultresult){
  2. @SuppressWarnings("unchecked")
  3. Messagemessage=sHandler.obtainMessage(MESSAGE_POST_RESULT,
  4. newAsyncTaskResult<Result>(this,result));
  5. message.sendToTarget();
  6. returnresult;
  7. }
可以看到,在这里是利用了sHandler来发送异步消息的,而sHandler是在AsynctTask中定义的,如下: [java] view plain copy
  1. privatestaticfinalInternalHandlersHandler=newInternalHandler();
InternalHandler定义如下
[java] view plain copy
  1. privatestaticclassInternalHandlerextendsHandler{
  2. @SuppressWarnings({"unchecked","RawUseOfParameterizedType"})
  3. @Override
  4. publicvoidhandleMessage(Messagemsg){
  5. AsyncTaskResultresult=(AsyncTaskResult)msg.obj;
  6. switch(msg.what){
  7. caseMESSAGE_POST_RESULT:
  8. //Thereisonlyoneresult
  9. result.mTask.finish(result.mData[0]);
  10. break;
  11. caseMESSAGE_POST_PROGRESS:
  12. result.mTask.onProgressUpdate(result.mData);
  13. break;
  14. }
  15. }
  16. }
我们可以在这里发现,如果是MESSAGE_POST_RESULT,则会调用mTask的finish方法,然后就结束了,而如果是MESSAGE_POST_PROGRESS,则会调用 onProgressUpdate方法,那么,很显然这个mTask应该就是我们定久的AsyncTask了吧。我们看看AsyncTaskResult是什么先, [java] view plain copy
  1. @SuppressWarnings({"RawUseOfParameterizedType"})
  2. privatestaticclassAsyncTaskResult<Data>{
  3. finalAsyncTaskmTask;
  4. finalData[]mData;
  5. AsyncTaskResult(AsyncTasktask,Data...data){
  6. mTask=task;
  7. mData=data;
  8. }
  9. }
我们发现,在上面传进来的AsyncTaskResult的参数task的正好就是this,而它又赋值给了mTask的,所以说明,这个mTask就是我们在Activity中定义的LoadImageTask了,而它是在主线程中定义的,那么很显然,它的finish方法也是在主线程,也就是UI线程中执行的了,再来看看这个finish方法: [java] view plain copy
  1. privatevoidfinish(Resultresult){
  2. if(isCancelled()){
  3. onCancelled(result);
  4. }else{
  5. onPostExecute(result);
  6. }
  7. mStatus=Status.FINISHED;
  8. }
在这里,我们终于看到了onPostExecute方法的调用了,这说明了,onPostExecute就是在UI线程中干活的了。最后mStatus也被设计成FIINISHED了,这个异步任务也就结束了。
转载自:http://blog.csdn.net/u013889308/article/details/20372481

更多相关文章

  1. Android实现简单底部导航栏 Android仿微信滑动切换效果
  2. Android动态加载补充 加载SD卡中的SO库
  3. Looper,Handler,Message
  4. [Android] - 对话框的小框架 Managed-Dialog
  5. [置顶] Android(安卓)View视图------Android如何创建一个view。
  6. Android开发注意点
  7. 第三方应用获得system权限
  8. Android(安卓)Handler机制之循环消息队列的退出
  9. Android中的Menu(菜单)的三种类型菜单的学习

随机推荐

  1. android:versionCode和android:versionNa
  2. Android图表控件MPAndroidChart——曲线
  3. Android(安卓)UI开发第一篇——android的
  4. Android(安卓)Studio 获取SHA1
  5. Android(安卓)众多的布局属性详解
  6. Android(安卓)多媒体扫描过程(Android(安
  7. android 电池(二):android关机充电流程、充
  8. 如何向Android模拟器打电话发短信
  9. Android图形系统的底层实现
  10. Android(安卓)PendingIntent实现原理和代