5.AsyncTask注意事项

注意事项:

  • 参数:
AsyncTask<Params,Progress,Result>: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;
        }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容