AsyncTask


AsyncTask是android将Handler和Thread继承好的一个类,在某些场景下使用它很方便。先介绍基本用法,然后看一下源代码,最后比较一下它与handler。

7.1 使用方法(点击这里查看官网介绍)
定义:AsyncTask类的定义:publicabstractclass AsyncTask<Params,Progress,Result>{ }
三个泛型参数的意义:
Params:execute时传入的参数类型
Progress:更新进度时的参数类型
Result:更新完成结果参数类型
如果不需要传入参数的话,使用java.lang.Void代替。
步骤:四个方法
1.onPreExecute():当我们调用execute方法后立马执行,在UI线程上运行,主要用来在设置一些标志。比如显示一个"正在运行中"进度对话框,及时给用户反馈。
2.doInBackground(Params ...):真正在子线程中执行的耗时操作,在onPreExecute方法执行完之后开始执行。可以在这里做一些耗时的操作,比如加载网络图片操作数据库,读写文件等等。可以将操作进度通过publicProgress(Progress ...)发送给UI线程,然后触发onProgessUpdate(Progress ...)方法。
3.onProgressUpdate(Progress...):当在doInBackground中调用publicProgress之后就会触发此方法,提示用户当前任务的进度。
4.onPostExecute(Result):当doInBackground方法执行完毕后。主要用来更新数据,比如展示下载完成的图片。
看一个简单的例子:class MyAsyncTask extends AsyncTask<Void,Integer,Void>
先看onPreExecute方法:   
  1. proteced void onPreExecute(){  
  2.          Log.d(TAG,"onPreExecute,thread id"+Thread.currentThread().getId());  
  3.          //一般都是显示进度对话框,提醒用户耐心等待  
  4.          dialog.show();  
  5.     }  
 proteced void onPreExecute(){
          Log.d(TAG,"onPreExecute,thread id"+Thread.currentThread().getId());
          //一般都是显示进度对话框,提醒用户耐心等待
          dialog.show();
     }
再看doInBackground:
  1. protected Void doInBackground(Void...params){  
  2.                //模拟耗时操作  
  3.                     for(int i=0;i<6;i++){  
  4.                          try{  
  5.                                    Thread.sleep(100);  
  6.                               }  
  7.                          catch(Exception e){  
  8.                          }  
  9.                          //更新界面  
  10.                          publishProgress(i);//每一次调用此方法,就会触发onProgressUpdate方法。下面会有分析  
  11.                          Log.d(TAG,"doInBackground,thread id"+Thread.currentThread().getId());  
  12.                     }  
  13.      }  
protected Void doInBackground(Void...params){
               //模拟耗时操作
                    for(int i=0;i<6;i++){
                         try{
                                   Thread.sleep(100);
                              }
                         catch(Exception e){
                         }
                         //更新界面
                         publishProgress(i);//每一次调用此方法,就会触发onProgressUpdate方法。下面会有分析
                         Log.d(TAG,"doInBackground,thread id"+Thread.currentThread().getId());
                    }
     }
如何更新进度:onProgressUpdate:   
  1. protected void onProgressUpdate(Integer...values){  
  2.          dialog.setProgress(values[0]);  
  3.          Log.d(TAG,"onProgressUpdate,thread id"+Thread.currentThread().getId());  
  4.     }         
 protected void onProgressUpdate(Integer...values){
          dialog.setProgress(values[0]);
          Log.d(TAG,"onProgressUpdate,thread id"+Thread.currentThread().getId());
     }       
最后执行完毕:onPostExecute     
  1. protected void onPostExecute(Void result){  
  2.           dialog.dismiss();  
  3.           Log.d(TAG,"onProgressUpdate,thread id"+Thread.currentThread().getId());  
  4.      }  
protected void onPostExecute(Void result){
          dialog.dismiss();
          Log.d(TAG,"onProgressUpdate,thread id"+Thread.currentThread().getId());
     }
运行结果:
可以看出,只有在doInBackground中是子线程中运行的,onPreExecuteonProgressUpdateonPostExecute都是在UI Thread中运行的。这也符合了"不要在非UI Thread中操作UI"的原则(关于UI线程点击这里)。
如何取消任务:
通过调用cancle方法,这样就会使得isCancelled()方法返回true。cancel之后当doInBackground方法执行结束之后执行onCancelled(Result)方法,不再执行onPostExecute(Result)方法。源码实现
  1. private void finish(Result result) {  
  2.        if (isCancelled()) {  
  3.            onCancelled(result);  
  4.        } else {  
  5.            onPostExecute(result);  
  6.        }  
  7.        mStatus = Status.FINISHED;  
  8.    }  
 private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }
通常做法是一直检测isCancelled方法返回值,这样能及时终止task。
  1. for(int i=0;i<10;i++){  
  2.     try{  
  3.         Thread.sleep(5*1000);  
  4.         if(isCancelled()){  
  5.             break;  
  6.         }  
  7.     }catch(Exception e){  
  8.     }  
  9. }  
for(int i=0;i<10;i++){
	try{
		Thread.sleep(5*1000);
		if(isCancelled()){
			break;
		}
	}catch(Exception e){
	}
}
注意:正确使用AsyncTask有几个原则:
1.AsynctTask对象必须是必须是在UI Thread中创建,且execute必须要UI Thread中调用。否则报错:Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()。因为AsyncTask中有Handler(关于Handler请看这里),且该Handler是处理UI线程中的messag队列,所以只能执行在UI线程创建和运行。
2.不要手动调用onPreExecute,doInBackground,onPostExecute等方法。因为AsyncTask的运行依靠的是线程池,handler、message,而这些成员变量的创建和运行时在execute方法中进行的。调用时要使用execute方法,否则也就失去了AsyncTask的作用。关于这个方法下面会介绍
3.不要在doInBackground中修改UI组件,上面已将证明过此方法是在子线程中执行。
4.一个AsyncTask实例只能执行一次,如果执行多次会报错。上源代码:
  1. if (mStatus != Status.PENDING) {  
  2.            switch (mStatus) {  
  3.                case RUNNING:  
  4.                    throw new IllegalStateException("Cannot execute task:"  
  5.                            + " the task is already running.");  
  6.                case FINISHED:  
  7.                    throw new IllegalStateException("Cannot execute task:"  
  8.                            + " the task has already been executed "  
  9.                            + "(a task can be executed only once)");  
  10.            }  
  11.        }  
  12.        mStatus = Status.RUNNING;    
 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;  
如果AsyncTask实例处于RUNNING或者FINISHED状态,则显示相应的异常

7.2 源码分析
先看上面所说的几种状态:    
  1. public enum Status{  
  2.          PENDING//还没有开始执行  
  3.          RUNNING//运行中  
  4.          FINISHED//执行完毕  
  5.     }  
 public enum Status{
          PENDING//还没有开始执行
          RUNNING//运行中
          FINISHED//执行完毕
     }
我们使用的时候是调用execute方法,所以来看execute方法,该方法执行execute()->executeOnExecutor(sDefaultExecutor , params),看一下executeOnExecutor方法:     
  1. public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,  
  2.            Params... params) {  
  3.        if (mStatus != Status.PENDING) {//如果不是pending状态会产生异常,这也是为什么一个task执行执行一次,请停止了不能再执行  
  4.            switch (mStatus) {  
  5.                case RUNNING:  
  6.                    throw new IllegalStateException("Cannot execute task:"  
  7.                            + " the task is already running.");  
  8.                case FINISHED:  
  9.                    throw new IllegalStateException("Cannot execute task:"  
  10.                            + " the task has already been executed "  
  11.                            + "(a task can be executed only once)");  
  12.            }  
  13.        }  
  14.        mStatus = Status.RUNNING;  
  15.        onPreExecute();//立马执行onPreExecute方法  
  16.        mWorker.mParams = params;  
  17.        exec.execute(mFuture);  
  18.        return this;  
  19.    }      
 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {//如果不是pending状态会产生异常,这也是为什么一个task执行执行一次,请停止了不能再执行
            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();//立马执行onPreExecute方法
        mWorker.mParams = params;
        exec.execute(mFuture);
        return this;
    }    
可以看出先执行的是onPreExecute方法。当然们也可以调用executeOnExecutor(自定一个executor),3.0之后系统默认通过了一个SerialExecutor用来调度线程池中的线程。
上面出现了mWorker,mFuture以及exec。先介绍mWorker,mFutrue、exec这三个变量。首先是mWorker:      
  1. mWorker = new WorkerRunnable<Params, Result>() {  
  2.             public Result call() throws Exception {  
  3.                 mTaskInvoked.set(true);  
  4.                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  5.                 return postResult(doInBackground(mParams));  
  6.             }  
  7.         };  
mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                return postResult(doInBackground(mParams));
            }
        };
如果执行了call方法,就会设置线程优先级,执行postResult(doInBackground(mParams))。此方法在线程池中执行。
然后是mFuture变量   
  1. mFuture = new FutureTask<Result>(mWorker) {  
  2.           @Override  
  3.           protected void done() {  
  4.               try {  
  5.                   final Result result = get();  
  6.                   postResultIfNotInvoked(result);  
  7.               } catch (InterruptedException e) {  
  8.                   android.util.Log.w(LOG_TAG, e);  
  9.               } catch (ExecutionException e) {  
  10.                   throw new RuntimeException("An error occured while executing doInBackground()",  
  11.                           e.getCause());  
  12.               } catch (CancellationException e) {  
  13.                   postResultIfNotInvoked(null);  
  14.               } catch (Throwable t) {  
  15.                   throw new RuntimeException("An error occured while executing "  
  16.                           + "doInBackground()", t);  
  17.               }  
  18.           }  
  19.       };  
  mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    final Result result = get();
                    postResultIfNotInvoked(result);
                } 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) {
                    postResultIfNotInvoked(null);
                } catch (Throwable t) {
                    throw new RuntimeException("An error occured while executing "
                            + "doInBackground()", t);
                }
            }
        };
exec类型为:SerialExecutor。只是3.0之后系统默认提供的一个线程池调度器。   
  1. private static class SerialExecutor implements Executor {  
  2.       final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();  
  3.       Runnable mActive;  
  4.       public synchronized void execute(final Runnable r) {  
  5.           mTasks.offer(new Runnable() {  
  6.               public void run() {  
  7.                   try {  
  8.                       r.run();  
  9.                   } finally {  
  10.                       scheduleNext();  
  11.                   }  
  12.               }  
  13.           });  
  14.           if (mActive == null) {  
  15.               scheduleNext();  
  16.           }  
  17.       }  
  18.       protected synchronized void scheduleNext() {  
  19.           if ((mActive = mTasks.poll()) != null) {  
  20.               THREAD_POOL_EXECUTOR.execute(mActive);//实际上每次只执行一个线程,3.0之后默认是这种方式,我们可改变这种行为。  
  21.           }  
  22.       }  
  23.   }  
  private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);//实际上每次只执行一个线程,3.0之后默认是这种方式,我们可改变这种行为。
            }
        }
    }
可以看出,将mActive(也就是mWorker)放在一个线程池中运行。也就是doInBackground方法在子线程中执行。最主要的是,这个调度器每次只会执行一个线程。当然我们也可以自己定义一个调度器进行线程的调度。
上面提到mWorker中涉及到postResult方法,再看postResult方法:  
  1. private Result postResult(Result result) {  
  2.        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,  
  3.                new AsyncTaskResult<Result>(this, result));  
  4.        message.sendToTarget();  
  5.        return result;  
  6.    }  
 private Result postResult(Result result) {
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
发送一个消息给sHandler处理,sHandler是InternalHandler类型(handler机制无处不在)。
  1. private static class InternalHandler extends Handler {  
  2.         @SuppressWarnings({"unchecked""RawUseOfParameterizedType"})  
  3.         @Override  
  4.         public void handleMessage(Message msg) {  
  5.             AsyncTaskResult result = (AsyncTaskResult) msg.obj;  
  6.             switch (msg.what) {  
  7.                 case MESSAGE_POST_RESULT://任务完成消息  
  8.                     // There is only one result  
  9.                     result.mTask.finish(result.mData[0]);  
  10.                     break;  
  11.                 case MESSAGE_POST_PROGRESS://进度更新消息  
  12.                     result.mTask.onProgressUpdate(result.mData);  
  13.                     break;  
  14.             }  
  15.         }  
  16.     }  
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;
            }
        }
    }
消息类型是MESSAGE_POST_RESULT时调用finish方法: 
  1. private void finish(Result result) {  
  2.       if (isCancelled()) {  
  3.           onCancelled(result);//如果cancel立马执行onCancelled方法  
  4.       } else {  
  5.           onPostExecute(result);//否则执行onPostExecute方法  
  6.       }  
  7.       mStatus = Status.FINISHED;//状态设置为finished  
  8.   }  
  private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);//如果cancel立马执行onCancelled方法
        } else {
            onPostExecute(result);//否则执行onPostExecute方法
        }
        mStatus = Status.FINISHED;//状态设置为finished
    }
该handler还可以处理MESSAGE_POST_PROGRESS,这也证明了publishProgress方法来更新进度 :      
  1. protected final voidpublishProgress(Progress... values) {  
  2.         if (!isCancelled()) {  
  3.             sHandler.obtainMessage(MESSAGE_POST_PROGRESS,  
  4.                     new AsyncTaskResult<Progress>(this, values)).sendToTarget();  
  5.         }  
  6.     }  
protected final voidpublishProgress(Progress... values) {
        if (!isCancelled()) {
            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();
        }
    }
发送消息给sHandler,消息类型是MESSAGE_POST_PROGRESS,调用onProgressUpdate方法。

如何调度异步任务: 
在3.0之前的系统中调度异步任务使用    
     
运行并发最多128个同时执行,等待队列中最多10个。
3.0之后系统使用是包装过的ThreadPoolExecutor,其实是使用的SerialExecutor来实现。这是一个单线程模型,也就是说每次只执行一个。
当然我们可以指定executor的值,可以查阅相关资料    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值