5.AsyncTask注意事项

注意事项:

  • 参数:
AsyncTask:Void,Integer,String,Object等,可以使任意类型或封装的对象。
AsyncTask定义了三种泛型类型 Params,Progress和Result。
    Params 启动任务执行的输入参数--execute()中传入的参数。
    Progress 后台任务执行的进度--publishProgress中传入的参数,onProgressUpdate中接收的参数。
    Result 后台执行任务最终返回的结果--例如:doInBackgroud中返回的boolean判断执行是否成功。
  • 不能在子线程生成Async实例

ASync中的Handler为静态变量,类加载的时候生成,如果在子线程中new Async,那么Handler也会new,此时子线程new Handler之前没有prepeare会报错。

  • execute只能在UI线程调用?

如果onPreExecute没有操作UI,其实也是可以的调用的。

  • AsyncTask是串行执行的,多个任务执行的时候一个一个等待。但是注意,每次execute操作,将任务封装放入队列,无论是等待还是执行,在execute的时候,就马上调用onPreExecute了。有可能该任务需要等待,但是该任务下的onPreExecute方法已经执行了。
  • AsyncTask默认是串行的,也可以并行操作
mAsyncTask = new MyAsyncTask(myCount);
mAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,myCount+"");

"AsyncTask并不适合进行特别耗时的后台任务,对特别耗时的任务,建议使用线程池。--开发艺术探索上所写,但是还并未理解"
可能是因为:多个任务时特别耗时的任务会影响后面的任务迟迟不能执行。用线程池并发的话,就没这样的问题了。

  • 一个AsyncTask对象,只能执行一次execute,前面分析源码的时候已经验证过了,Running或者Finished的时候再执行都会报错。
  • 无论在任何线程,任何地方使用AsyncTask,因为该类内部的sDefaultExecutor是static类型,都将只有一个线程池对象。所以,AsyncTask的任务都是在这一个线程池中执行。
    所以,任何线程,任何地方,单次或多次调用AsyncTask执行,都是会放入队列,串行执行的。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;   
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();


AsyncTask 缺陷/坑:

  • AsyncTask有多个版本,多种实现,不具体分析。
    总之,在3.0以前,最大支持128个线程的并发,10个任务的等待。并发执行,不用等待。超过138个任务同时执行,会发生异常:java.util.concurrent.RejectedExecutionException 。
    在3.0以后,无论有多少任务,都会在其内部单线程一个一个执行;

  • 异常问题:

Activity退出时,记得在onDestroy中cancle,并在AsyncTask做isCancel检查操作,确定Async代码是否执行。否则,有坑能退出Activity的时候Async还没有执行完,Async执行完要更新UI的时候View已经销毁。

  • 内存泄漏问题:
    1.Java特性,AsyncTask类在Activity是非静态内部类的时候,默认持有外部类Activity的引用。
    2.AsyncTask持有Activity中的变量,如View。

如何避免:
静态内部类。activity若引用,使用activity变量的时候判断null。例如前篇,Handler防止内存泄漏一样。


取消操作任务操作时,AsyncTask不能中断的处理。

cancel的时候,并不能中断已经开始的任务,因为不能中断正在执行的Thread(但是测试的可以中断正在执行的Async,看下面"不确定",这里就按大部分人说的不能中断的情况下)。

    //AsyncTask方法
    public final boolean cancel(boolean mayInterruptIfRunning) {
        //标记
        mCancelled.set(true);
        return mFuture.cancel(mayInterruptIfRunning);
    }    
    
    //FutureTask方法
    public boolean cancel(boolean mayInterruptIfRunning) {
        if (!(state == NEW &&
              U.compareAndSwapInt(this, STATE, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                    //中断子线程。应该是不能中断的,但是测试是可以中断的。
                        t.interrupt();
                } finally { // final state
                    U.putOrderedInt(this, STATE, INTERRUPTED);
                }
            }
        } finally {
            //最后调用onCancle()方法
            finishCompletion();
        }
        return true;
    }

mCancelled.set(true);只是在AsyncTask中一个标记,说明是否执行过中断操作,至于有没有中断成功isCancelled()的返回值并不能说明。 t.interrupt();才是执行中断线程的主要代码,现在并不确定该方法是否能中断线程(网上说不能中断,而我测试可以中断)。

解决办法:

  • 在AsyncTask执行的代码中,判断是否中断,isCancelled();
  • 如果后台任务有频繁的while操作,可以添加Thread.sleep(1)。因为interrupt的时候,会使阻塞的线程抛异常,捕获异常后return结束doInBackgroud方法。

不确定:

  • 中断任务:

Thread/AsyncTask不能中断。Java线程在执行的时候,并不能中断该线程,同样AsyncTask也是。但是测试的结果是,Thread不能中断,AsyncTask可以中断。
按说,它们都是把执行的代码封装到了Runnable,开子线程执行。但测试就是Thread中断了,AsyncTask没有中断。

//testThread.interrupt();不能中断
public class TestRunnable implements Runnable {
        private static final String TAG = "TestRunnable";
        private int count = 0;

        @Override
        public void run() {
            while (count < 1000) {
                Log.e(TAG, "run: count=" + count);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                   //interrupt会使阻塞的线程抛该异常。也可以利用这个特性,中断任务。抛异常的时候return。
                   // return;
                }
                count++;
            }
        }
    }
// mAsyncTask.execute(count + ""); 按说也因该不能中断的,但是,测试的时候就是中断了啊。
        @Override
        protected Boolean doInBackground(String... params) {
            while (currentProgress <= 100) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    //return false;
                }
                currentProgress++;
            }
            return true;
        }

你可能感兴趣的:(5.AsyncTask注意事项)