【问题标题】:Android: How to retain AsyncTask instance when Activity gets destroyed?Android:当 Activity 被销毁时如何保留 AsyncTask 实例?
【发布时间】:2012-08-04 20:00:12
【问题描述】:

在我的应用程序中,我有一个继承自 AsyncTask 的类,它从服务器下载大量数据。我使用ProgressBar 来指示下载进度。

当用户点击HOME 键时,这个AsyncTask 所附加到的Activity 被破坏,但下载继续。

如何重新附加此AsyncTask 并向用户显示进度?我尝试使用onRetainNonConfigurationInstance,但 Android 4.0 似乎没有调用此方法。我的应用程序不使用Fragments API。

【问题讨论】:

    标签: android android-asynctask


    【解决方案1】:

    我在这种情况下做了如下:

    1. 我创建了一个IntentService 来处理与服务器的通信。这既有AsyncTask 的一些好处(例如,工作线程),也有服务的一些好处(随时随地可用)。
    2. 可以通过我的主 Activity 中的用户操作或通过 inexact repeating alarm 调用 IntentService。
    3. 数据存储在SQLite database 中,前面是ContentProvider。我通过使用 SQLiteOpenHelper 并从后台 IntentService 的安全性调用 getWritableDatabase() 来回避何时/如何创建我的数据库和表的问题。
    4. 任务完成后,如果我的主 Activity 未处于活动状态,它会发布 Notification

    这种安排的一个好处是,不需要进度条。事实上,不需要 UI。用户在服务运行时继续使用应用程序,并且 UI 会在新数据进入 ContentProvider 时自动刷新。它的另一个优点是它比 AsyncTask 编写的代码更少。它通过从数据库中读取最后一个条目的服务器端元数据并要求用户在该点之后开始,自动从上次中断的地方开始。由于它不与任何 Activity 实例相关联,因此它不关心 onPostExecute()configuration changes 或其中任何一个。而且您不必担心像 AsyncTask 这样的单次执行。

    【讨论】:

    • +1 建议IntentService。但是,我要补充的一件事是,如果 OP 确实需要进度指示,实际上可以发布多个正在进行的 Notifications,其中包含 ProgressBar 或者可能只是文本进度信息。
    • 感谢您的补充,Squonk。在我的应用程序中,我的 ListView 中新行的存在隐含地表明了进展。但是这个模型不适合下载一个大文件。
    • 好的,很好听。我的理解还有一个问题:我使用一些 AsyncTask 来准备 SQL 临时表以在我的活动中使用,并且我没有 ContentProvider 。在这种情况下我应该使用什么?
    • 我应该使用从简单的 HTTP 请求到服务器的服务而不是 AsyncTask 吗?
    • 我使用 IntentService 主要是因为我很懒,而且它看起来比 AsyncTask 编写的代码更少。无法访问 Activity 中的任何成员变量是一个挑战,但最好不要依赖它。对于创建 SQL 表,您可以采取任何一种方式:您不太可能在中间丢失 Activity。向调用活动返回消息状态可能是一个问题。你注意到了,我不使用直接的双向通信。
    【解决方案2】:

    如果需要在后台下载大量数据,我会使用服务而不是 AsyncTask。来自 Google IO 的 presentation 很好地介绍了使用服务。

    引用自 AsyncTask 文档:

    如果你需要让线程长时间运行,它是 强烈建议您使用由 java.util.concurrent 包,例如 Executor、ThreadPoolExecutor 和 未来任务。

    该任务只能执行一次(如果尝试第二次执行将抛出异常。)

    据我了解,您无法继续执行上一个 AsyncTask。 不过,您可以部分加载数据并保存读取的数据量,然后启动新的 AsyncTask,该任务将从上次保存的点开始。从我的角度来看,当活动进入后台时暂停加载并不是最好的主意,最好使用服务来完成已启动的内容。

    【讨论】:

    • +1 同意 - 对于运行时间更长的任务,请使用服务。出于好奇,有没有办法在 AsyncTask 完成时收到通知,然后在旧的 Activity 实例被销毁时调用新的 Activity?
    • @SagarHatekar 使用 onPostExecute() 方法创建一个意图,如果旧的活动尚未运行,则启动一个新的活动。
    • 它不再是任务 - 最大时间是 10 秒,我不能保存部分数据然后从保存点开始。如果任务未完成,我需要再次显示进度对话框并附加 Activity 以调用 OnTaskComplete 回调。
    • 我认为你不能确定当 Activity 已经被销毁时会调用 onPostExecute 。 UI线程可能已经停止,因此您的发布结果的消息将不会被接收。
    • 如果不是一个很长的任务,那么你不必太担心你的活动会被破坏,它只会被停止。
    【解决方案3】:

    您是否考虑过使用服务将您的 AsyncTask 附加到?将其视为永久运行的服务可能是您手头任务的最佳解决方案。那么您所要做的就是检查服务是否正在运行以及您的下载是否正在运行(使用静态布尔变量很容易完成)然后您只需使用服务中的一些状态保存变量创建一个进度对话框(可能是百分比下载的总文件大小等)在您的主要活动的 onCreate 方法中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多