坑爹的AsyncTask之根本停不下来

作者: 尹star | 来源:发表于2015-11-21 15:22 被阅读1489次

上篇《坑爹的AsyncTask之内存泄露》已经简单的探讨过线程使用不当会造成内存泄露的问题,在Activity中如果一个线程超出了Activity的生命周期是极有可能发生内存泄露的,那简单来说我们不让线程的生命周期长于Activity就能从根本上解决这个问题。我们今天探讨的主题就是如何让一个Run起来的线程去stop。

听起来有点不可思议,因为JAVA语言中并没有提供相应的API来停止一个正在运行的线程,再来看看我们Android中的“无忧线程”AsyncTask,源码看下来找到一个cancel()方法,看起来似乎是用来cancel当前线程的,写个demo测试下究竟,结果发现这货根本不靠谱。不可能啊,难道Android会提供不靠谱的API给开发者用嘛,回头再来看看cancel()方法的API说明

* <p>Calling this method will result in {@link #onCancelled(Object)} being 
* invoked on the UI thread after {@link #doInBackground(Object[])} 
* returns. Calling this method guarantees that {@link #onPostExecute(Object)} 
* is never invoked. After invoking this method, you should check the 
* value returned by {@link #isCancelled()} periodically from 
* {@link #doInBackground(Object[])} to finish the task as early as 
* possible.</p >

这段注释大概是说,如果调用cancel()方法,它不会立即执行,只有当doInBackground()方法执行完有返回值之后,会在UI主线程调用cancel(),同时也会间接的调用iscancelled(), 并且返回true ,这个时候就不会再调onPostExecute(),然后在doInBackground()里定期检查iscancelled()方法的返回值,是否被cancel,如果return true,就尽快停止。从这段注释里我们似乎发现cancel()方法本身就不太靠谱,因为它的调用在doInBackground()之后执行,假如我就想在doInBackground()里停止当前线程是不是就没有办法了,不保险加不靠谱,我们通过cancel()方法终止线程的想法显然走不通。

但是这段注释似乎给了我们一些启示,可以通过定期检查返回值的方法来判断是否需要停止当前线程。我们要知道在java中,是没有提供相关API来停止一个正在运行中的线程,而Android的AsyncTask也是一样的。如果必须要停止一个线程,我们可以合理利用Java中的Exception,让这个线程在检查到自己需要被停止的时候抛出异常,然后线程就不会再继续执行了,那怎么操作呢,我们可以在这个线程中的耗时操作中设置一些flag,也就是AsyncTask的doInBackground方法中的某些关键步骤。然后在外层需要终止此线程的地方改变这个flag值,线程中的耗时代码一步步执行,当某一时刻发现flag的值变了,throwException,线程就不会再继续执行了。为了保险起见,在外层我们还要捕获这个异常,进行相应处理。

看到这里你是否对这个粗暴的暂停办法留有疑问呢?这样做安全吗,如此粗暴的直接打断AsyncTask真的好么?关于安全问题,如果是在主线程上发生有未处理的异常,将直接导致整个进程终止,简单说就是要用程序fc。但是我们是在AsyncTask的doInBackground方法中打断线程的,doInBackground方法是子线程,子线程被发生异常后会自己死掉而不会引起其他问题,更不会影响到主线程,更何况我们为了更加安全还捕获了异常并做处理,所以这个办法还是安全的,亲测有效。

我们找到了停止Running线程的办法,那么下次只要在Activity生命周期结束之前也结束掉线程的生命,就可以让你的应用程序更加安全健壮了。

如有刊误,欢迎指正。

相关文章

  • 坑爹的AsyncTask之根本停不下来

    上篇《坑爹的AsyncTask之内存泄露》已经简单的探讨过线程使用不当会造成内存泄露的问题,在Activity中如...

  • 坑爹的AsyncTask之内存泄露

    当AsyncTask被引入到Android中时,它被贴上“无忧线程”的标签。其目的是让与UI线程交互的子线程变得更...

  • 坑爹

    坑爹…豆瓣就是个坑爹货

  • 坑爹的爹坑

    01 村里的奇葩事,真事!就是奇葩的让人咂舌。张明白有一个‘奇葩’的爹,人称张算计。 清明节,村里的张算计死了。人...

  • Android AsyncTask 详解

    Android AsyncTask 详解 内容划分 AsyncTask简介 简单使用 繁杂部分和源码浅析 一些坑的...

  • 坑爹?爹挖的坑

    坑爹的儿子都是被爹坑的 白米先生 字数 474 · 阅读 1 2020-06-13 09:35 说起来像绕口令。 ...

  • 坑爹的爹

    2023年1月31日 星期三 下午4:44 昨晚上娃爹又一晚上没回来了! 第一次一晚上跟他正面对决!从来没有这么直...

  • 2018-02-08

    坑爹,坑娘。还没见过坑儿子的

  • 奥本海默——一个坑爹的特例

    坑爹算不上新的发明,古今中外,被坑惨了的爹不在少数。那些坑爹的主儿,大都年少轻狂、不学无术。 不过,凡事都有例外。...

  • 常说坑爹熊孩子, 却很少听闻坑孩子的爹! 盘点那些娱乐圈最坑娃的

    坑爹常有,而坑娃不常有。故虽有坑娃的爹,却鲜为人知! 生活中,就时常会看到坑爹的熊孩子,因为或肆无忌惮,或荒诞不羁...

网友评论

  • 3f81e99e0c01:首先flag 需要使用volatile关键字修饰,其次,终止一个线程分为好几种情况,这种方法并不完美哦,还有,亲,你那篇关于context的文章非常好,介意转载不??
    尹star: @MelchizedekL 可以😊
  • bbcdd2142202:既然设置了flag标志,那为什么不正常退出(通过return),而是抛出异常来退出呢?求指教!
    尹star: @uurun return线程已经开启了~还是要继续跑的
  • hiLily:Java的线程停止不都是这样玩的嘛,楼主标题党了哈:relieved:

本文标题:坑爹的AsyncTask之根本停不下来

本文链接:https://www.haomeiwen.com/subject/txalhttx.html