AsyncTask源码分析

来源:互联网 发布:mac office软件下载 编辑:程序博客网 时间:2024/06/09 21:01

    • AsyncTask简介
    • AsyncTask步骤
    • 注意事项
    • AsyncTask工作原理
    • 解决30以上版本不能并行执行的问题

AsyncTask简介

  • AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。

  • AsyncTask实际上就是封装了Thread和Handler,可以让我们在后台进行计算并且把计算的结果及时更新到UI上,而这些正是Thread+Handler所做的事情,AsyncTask的作用就是简化Thread+Handler

  • 在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务

AsyncTask步骤

一个异步任务的执行一般包括以下几个步骤:

1.execute(Params… params):

执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。

2.onPreExecute():

在execute(Params…params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。在主线程中执行。

3.doInBackground(Params…params):

在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress…values)来更新进度信息。在线程池中执行。

4.onProgressUpdate(Progress…values):

在调用publishProgress(Progress…values)时,此方法被执行,直接将进度信息更新到UI组件上。 在主线程中执行。

5.onPostExecute(Result result):

当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。在主线程中执行。

注意事项

1.异步任务的实例必须在UI线程中创建。
2.AsyncTask的类必须在UI线程加载(从4.1开始系统会帮我们自动完成)
3.execute(Params… params)方法必须在UI线程中调用。
4.不要在你的程序中去直接调用onPreExecute(), onPostExecute, doInBackground, onProgressUpdate方法
一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
5.不能在doInBackground(Params… params)中更改UI组件的信息。
6.一个AsyncTask对象只能执行一次,即只能调用一次execute方法,否则会报运行时异常
7.AsyncTask不是被设计为处理耗时操作的,耗时上限为几秒钟,如果要做长耗时操作,强烈建议你使用Executor,ThreadPoolExecutor以及FutureTask
8.在1.6之前,AsyncTask是串行执行任务的,1.6的时候AsyncTask开始采用线程池里处理并行任务,但是从3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask又采用一个线程来串行执行任务

AsyncTask工作原理

AsyncTask启动首先会调用execute,先从execute方法开始分析,execute又会调用executeOnExecutor,它们的实现如下:

  @MainThread    public final AsyncTask<Params, Progress, Result> execute(Params... params) {        return executeOnExecutor(sDefaultExecutor, params);    }    @MainThread    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;    }

sDefaultExecutor实现了一个串行的线程池,一个进程中所有的AsyncTask都会在这个线程池中排队。onPreExecute会先执行。然后通过exec.execute(mFuture)执行这个线程池。

/**      * Creates a new asynchronous task. This constructor must be invoked on the UI thread.      */      public AsyncTask() {          mWorker = new WorkerRunnable<Params, Result>() {              public Result call() throws Exception {                  mTaskInvoked.set(true);                  Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                  //noinspection unchecked                  return postResult(doInBackground(mParams));              }          };          mFuture = new FutureTask<Result>(mWorker) {              @Override              protected void done() {                  try {                      postResultIfNotInvoked(get());                  } 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);                  }              }          };      }  

首先系统会把AsyncTask的mParams参数封装为FutureTask对象,FutureTask是一个并发类。接着这个FutureTask会交给SerialExecutor的execute方法去处理,execute首先会把FutureTask插入任务队列mTasks,详细实现如下:

/*串行执行器的实现,我们要好好看看,它是怎么把并行转为串行的  *目前我们需要知道,asyncTask.execute(Params ...)实际上会调用  *SerialExecutor的execute方法,这一点后面再说明。也就是说:当你的asyncTask执行的时候,  *首先你的task会被加入到任务队列,然后排队,一个个执行  */  private static class SerialExecutor implements Executor {      //线性双向队列,用来存储所有的AsyncTask任务      final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();      //当前正在执行的AsyncTask任务      Runnable mActive;      public synchronized void execute(final Runnable r) {          //将新的AsyncTask任务加入到双向队列中          mTasks.offer(new Runnable() {              public void run() {                  try {                      //执行AsyncTask任务                      r.run();                  } finally {                      //当前AsyncTask任务执行完毕后,进行下一轮执行,如果还有未执行任务的话                      //这一点很明显体现了AsyncTask是串行执行任务的,总是一个任务执行完毕才会执行下一个任务                      scheduleNext();                  }              }          });          //如果当前没有任务在执行,直接进入执行逻辑          if (mActive == null) {              scheduleNext();          }      }      protected synchronized void scheduleNext() {          //从任务队列中取出队列头部的任务,如果有就交给并发线程池去执行          if ((mActive = mTasks.poll()) != null) {              THREAD_POOL_EXECUTOR.execute(mActive);          }      }  }  

SerialExecutor实现了AsyncTask的排队过程。ArrayDeque 类提供了可调整大小的阵列,并实现了Deque接口。从任务队列中取出队列头部的任务,如果有就交给并发线程池HREAD_POOL_EXECUTOR去执行。

THREAD_POOL_EXECUTOR线程池用于真正执行任务。

//获取当前的cpu核心数  private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();  //线程池核心容量  private static final int CORE_POOL_SIZE = CPU_COUNT + 1;  //线程池最大容量  private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;  //过剩的空闲线程的存活时间  private static final int KEEP_ALIVE = 1;  //ThreadFactory 线程工厂,通过工厂方法newThread来获取新线程  private static final ThreadFactory sThreadFactory = new ThreadFactory() {      //原子整数,可以在超高并发下正常工作      private final AtomicInteger mCount = new AtomicInteger(1);      public Thread newThread(Runnable r) {          return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());      }  };  //静态阻塞式队列,用来存放待执行的任务,初始容量:128个  private static final BlockingQueue<Runnable> sPoolWorkQueue =          new LinkedBlockingQueue<Runnable>(128);  /**  * 静态并发线程池,可以用来并行执行任务,尽管从3.0开始,AsyncTask默认是串行执行任务  * 但是我们仍然能构造出并行的AsyncTask  */  public static final Executor THREAD_POOL_EXECUTOR          = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,                  TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  

WorkerRunnable的call()方法最终会在线程池中执行,如下

    mWorker = new WorkerRunnable<Params, Result>() {              public Result call() throws Exception {                  mTaskInvoked.set(true);                  Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                  //noinspection unchecked                  return postResult(doInBackground(mParams));              }          };            

mTaskInvoked.set(true),表示当前任务已经被调用,然后执行doInBackground方法,接着返回值传递给postResult()方法,如下:

//doInBackground执行完毕,发送消息      private Result postResult(Result result) {          @SuppressWarnings("unchecked")          Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,                  new AsyncTaskResult<Result>(this, result));          message.sendToTarget();          return result;      }  

postResult会通过sHandler发送一个MESSAGE_POST_RESULT的消息。sHandler实现如下:

//AsyncTask内部Handler,用来发送后台计算进度更新消息和计算完成消息      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;              }          }      }  

sHandler收到MESSAGE_POST_RESULT后会调用finish方法,如果被取消任务,就调用onCancelled,否则调用onPostExecute:

//任务结束的时候会进行判断,如果任务没有被取消,则onPostExecute会被调用      private void finish(Result result) {          if (isCancelled()) {              onCancelled(result);          } else {              onPostExecute(result);          }          mStatus = Status.FINISHED;      }

解决3.0以上版本不能并行执行的问题

直接调用executeOnExecutor:
new MyAsyncTask(“AsyncTask#1”).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,”“);

1 0
原创粉丝点击