为什么Android AsyncTask的使用要遵循五大原则

引言

AsyncTask是一个围绕Handler和Thread而设计的助手类,封装了在工作线程中与UI交互的细节,只需要对应重写几个回调方法即可,并使得代码更加简洁,优雅。但要注意的是AsyncTask并不能是一个通用线程框架,这在Android官方介绍中有提到:

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework.

遵守五大原则的原因

看过官方文档的童鞋都应该知道,在使用AsyncTask时需要遵循五大原则,分别是:

  1. AsyncTask 类必须在UI线程中被加载,在JELLY_BEAN版本后将会自动完成。

  2. AsyncTask的实例化必须在UI线程中完成。

  3. AsyncTask的execute(Params...)方法必须在UI线程中被调用。

  4. 不需要手动调用 这些方法:onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)

  5. 一个AsyncTask实例只能被执行一次(第二次执行将会抛出异常)。

一开始使用时我也只是牢记这些原则,但是知其然而不知其所以然让我很难受(我不是处女座的::>.<:😃,所以决定好好看下源码分析下,以下为个人分析收获:

  1. AsyncTask的execute(Params...)方法必须在UI线程中被调用,原因是在execute(Params...)方法中调用了onPreExecute()方法,onPreExecute()方法是在task开始前在UI线程进行若干准备工作,例如:初始化一个进度条等,所以必须要在UI线程下执行。

  2. 不用手动调用,是因为那些方法都是回调方法,只需要实现或重写即可。

  3. 一个AsyncTask实例只能被执行一次,这是为了线程安全,当AsyncTask在直接调用executeOnExecutor()方法进入并行模式时,避免同一个任务同时被执行而造成混乱(当然你连续初始化两个实例submit我也没办法=。=),因为并行模式时各线程间是无序执行的。

其他注意点

另外在使用AsyncTask时还有一下几点需要额外注意:

  1. 在官方文档中有明确写到,AsyncTask理想情况下应该用作于一些短操作(最多几秒钟),特别是当在串行模式时(调用默认的execute()方法),每个任务都会FIFO顺序执行,若某一个task任务时间过长,则会造成后面的任务堆积,UI界面无响应(不是之ANR,而是指UI没更新)。

  2. 在3.0版本后AsyncTask默认是串行模式的,默认使用SerialExecutor线程池,它是以静态常量的形式存在的,模仿的是单一线程池的效果,同一时刻只会有一个线程正在执行,其余的均处于等待状态。
    所以无论你创建多少个继承了AsyncTask的子类,每次执行时仍会按加入的先后顺序执行且每次只执行一个。

  3. AsyncTask有cancel方法,当调用后它会取消正在执行的task,并在 doInBackground(Params...)之后不执行onPreExecute()和publishProgress()方法,而是直接执行onCancelled(result)方法。

     public final boolean cancel(boolean mayInterruptIfRunning) {
         mCancelled.set(true);
         //FutureTask是一个可以取消的异步计算类
         return mFuture.cancel(mayInterruptIfRunning);
     }
    

    但我们仍需注意的是,在cancel(boolean)后,doInBackground(Params...)是仍会执行直至结束的,所以更高效的方法应该是在doInBackground(Params...)方法中和onPreExecute()以及publishProgress()一样,设置一个 isCancelled()是否为false的判断,在决定是否继续执行下去。

     To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
    

结语

终于知其所以然了,好爽,哈哈。AsyncTask与handler和Thread相比的确是代码简洁了不少,而且逻辑结构清晰明了,缺点的就很明显了,就是自由度差了点,毕竟AsyncTask与UI线程通信其实还是依靠内部封装了一个sHandler,所以具体使用场景主要还是看大家的需求了。
至于AsyncTask的源码分析我就不再赘述了,网上关于这方面的资料也是很多,而且AsyncTask的源码本身不多,只有六七百行而且比较好理解,有能力还是自己看一遍源码较好,毕竟原汁原味嘛,哈哈。

参考链接:

  1. 官方文档AsyncTask
  2. 官方文档Processes and Threads
  3. Android AsyncTask完全解析

作者:XycZero
查看原文:http://www.xyczero.com/blog/article/21/.

posted @ 2015-03-22 21:08  xyczero  阅读(1855)  评论(2编辑  收藏  举报