zoukankan      html  css  js  c++  java
  • [翻译]The dark side of AsyncTask

      很好的一篇文章,非常适合初学者了解 AsyncTask,居然百度不出来。这篇博文是从俄语翻译成英语的,再从英语二次翻译过来。

      作者:+Fré Dumazy(?)

      原文链接:http://bon-app-etit.blogspot.jp/2013/04/the-dark-side-of-asynctask.html

      AsyncTask的黑暗面

      大家好,在这篇博文里我会向大家介绍一些 AsyncTask少有人知的黑暗面。半年前我第一次发文介绍 AsyncTask的用法。现在我要告诉你们这些用法可能会导致什么样的问题,以及如何解决这些问题。

      AsyncTask

      AsyncTask是在 Android1.5版本加入的,初衷是为了方便开发者管理线程。早在 Android1.0和1.1版本,AsyncTask也被称为 UserTask。你可以在你的工程源码里直接替换 AsyncTask为 UserTask以便支持低版本,但根据 Android官方统计,目前只有不到0.1%的设备运行在这些低版本上,你完全可以选择不支持低版本。

      现在使用 AsyncTask可能是最常用的 Android后台处理方法。它确实很容易上手,但这个类存在着一些容易被忽略的问题。

      LifeCycle

      这是 AsyncTask很容易被误解的一点。程序猿们可能认为当创建 AsyncTask的 Activity被销毁时,AsyncTask对象也会被销毁。但通常情况下,AsyncTask会继续执行它的 doInBackGround方法直到结束。AsyncTask的结束有两种情况:1. 外部调用了 cancel方法,会执行 onCancelled;2. 正常执行完成并调用 onPostExecute方法。

      假设 AsyncTask在 Activity销毁之前没有被取消,这可能会引起 AsyncTask的 crash,原因是 AsyncTask里所引用的 Activity中的 View等对象已经不存在了。所以我们需要确保 Activity销毁时调用了 AsyncTask的 cancel方法。cancel方法需要传入一个 boolean参数(mayInterruptIfRunning),来标识是否打断正在执行的 task。如果设置为 false,那么即使调用了 cancel方法,正在执行中的 AsyncTask也会执行完成。如果你的 doInBackGround方法中有循环语句的话,你需要在每次循环的时候都检查一下这个标志位。

      因此,我们应当确保使用正确的方法来取消 AsyncTask。

      

      Does cancel() really work?

      简而言之:有时候会。

      如果使用 cancel(false),正在执行中的 AsyncTask会一直执行直到完成,但这个方法可以阻止 onPostExecute方法被调用。因此很多情况下使用 cancel(false)是没有意义的(注:我们做 cancel操作不只是阻止 onPostExecute中的更新,也非常希望能立即停止 doInBackGround中那些开销较大的动作)。那你可能会想,无论如何都使用 cancel(true)不就可以了?错,如果 mayInterruptIfRunning标志位被置为 true,那只代表系统会尽可能早的结束 AsyncTask,如果在 doInBackGround中的操作是不可打断的,那 cancel(true)实际上也起不到立即结束 AsyncTask的功能。

      Memory leaks

      AsyncTask的 doInBackGround方法运行在后台线程,而其他一些方法运行在主线程,因此在 AsyncTask的生命周期内会始终保留一个对 Activity的引用,即便是 Activity已经被销毁,但在 AsyncTask中还是保留着引用。这可能会导致内存泄露。

      Losing your results

      另一个问题是随着 Activity的重启,我们可能会失去 AsyncTask的运行结果。例如横竖屏切换时,Activity被销毁然后重建,但 AsyncTask中存有的还是原来被销毁的那个 Activity的引用,所以 onPostExecute方法会不起作用。解决方法是,你可以在 Application等不会被销毁的对象中创建一个 AsyncTask。Activity.onRetainNonConfigurationInstance()和 Fragment.setRetainedInstance(true) 可能也会对这种情况有所帮助。

      Serial or parallel?

      很多人都对 AsyncTask是并行还是串行心存疑惑,原因是 AsyncTask的运行方式随着 Android版本的不同变更过几次。你可能会质疑我所说的“AsyncTask可能是并行或是串行”。假设你的方法中有如下两行代码:

    new AsyncTask1().execute();
    new AsyncTask2().execute();

      Task2会与 Task1同时开始吗?还是 Task2会在 Task1结束之后才开始运行?

      答案是:依赖于它们编译的 Android版本。

      在 Android1.6之前:

      第一版的 AsyncTask是串行的,意味着只有前一个 Task结束后下一个 Task才能开始运行。这可不是一种好的方式。

      Android1.6至 Android2.3:

      Android开发团队决定把 AsyncTask的运行方式改为并行,这样多个 AsyncTask可以同时运行在不同的后台线程中。这有一个问题,很多开发者已经习惯于串行的方式,这种改变会导致很多并发问题。

      Android3.0至今:

      “嘿嘿,他们习惯并发了?那我们改回去~!Let's Rock...” AsyncTask又被改为串行方式了。当然 Android开发团队也提供了并行的方式,就是使用 This is done by the method executeOnExecutor(Executor)方法,可以去 API文档中了解更多有关这个方法的信息。

      如果我们想自己控制运行方式,保证 AsyncTask始终并行,那可以用以下的代码(API level1~3不适用):

    public static void execute(AsyncTask as) {
     if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1) {
      as.execute();
     } else {
      as.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
    }

      Do we need AsyncTask?

      并不是这样的。用少量代码实现后台运行实际上并不困难,但我们也知道要想不出错的话需要考虑的非常周全。另一种执行后台操作的方法是使用 Loaders。这个类在 Android3.0被引入,也可以通过使用 library导入。我可能今后还会在写一篇关于如何使用 Loaders的博文,所以多关注我的博客吧:) (最后一句是作者的原话 哈哈)

      

  • 相关阅读:
    机器学习第二章复习
    机器学习第三章复习
    机器学习第四章复习
    第一次作业
    第二次作业
    第06组 Beta版本演示
    第06组 Beta冲刺(4/4)
    第06组 Beta冲刺(3/4)
    第06组 Beta冲刺(2/4)
    第06组 Beta冲刺(1/4)
  • 原文地址:https://www.cnblogs.com/haitong/p/3821704.html
Copyright © 2011-2022 走看看