【问题标题】:Handling "blocking" long running operations in Android在 Android 中处理“阻塞”长时间运行的操作
【发布时间】:2014-01-16 08:06:51
【问题描述】:

有一种常见的应用程序行为模式,即除非当前操作完成,否则您无法进行下一步。一个很好的例子是身份验证:一旦您向应用程序提供了登录名和密码,然后点击“登录”,该应用程序将阻止一段时间,向您显示一种“等等,我正在工作”指示符。即使这个任务很常见,我也没有设法在谷歌上找到一个“典型”的解决方案。

我牢记的要点:

  1. 绝对不能保证 Activity 的生命周期。活动保证在用户启动它们时启动,但是它们可以随时被终止。因此,一般而言,应将活动视为交互点,您的应用程序和用户可以在其中讨论他们的“愿望”。 始终由用户开始讨论。

  2. 另一方面,有一些服务,即从不直接与用户对话的组件。 服务生命周期保证,因此它似乎是放置处理逻辑的正确位置。

所以,对于我一开始描述的任务,公平地说:

  1. 应该有一个登录活动。
  2. 此活动应该能够以 4 种模式运行:
    • 清理/刚刚开始/用户尚未按下按钮。
    • 用户刚刚按下按钮,我们正在与 Web API 对话 - 这是长期运行的任务,我们希望显示一种 ProgressDialog。
    • 我们设法与 Web API 对话,它说一切正常。在这里,我们可能会完成这项活动并开始一项更有用的活动 - 用户在启动应用时最初希望看到的活动。
    • 要么我们没有设法与 Web API 对话,要么它说用户凭据有问题。在这种情况下,我们会显示一条错误消息。
  3. 应该有 Service 负责与 Web API 对话。

所以,这里有一个问题:

我如何正确地让 Activity 知道 4 种模式中的哪一种当前应该处于活动状态?

我所考虑的:

  1. Activity + AsyncTask。根本不起作用,因为AsyncTask 绑定到特定的Activity 实例,并且一旦重新创建Activity(例如设备方向更改),AsyncTask 就绑定到“错误”上下文。

  2. Activity + IntentService。 Activity 触发服务并在Intent 中提供“请求上下文”。一旦IntentService 完成,它使用sendBroadcast() 告诉Activity 我们在哪里。这不起作用,因为在 IntentService 完成时,Activity 已经可以暂停,因此它不会收到更新。

  3. 与第 2 页相同,但使用 sendStickyBroadcast()。这解决了错过更新的问题,但谷歌表示这是一种不好的做法,因为有一些开销之王或其他原因。

  4. 使用IntentService + ContentProvider + Loader。 Activity 触发服务并在Intent 中提供“请求上下文”。请求上下文有一个神奇的“请求令牌”。该令牌描述了“做某事的独特意图”,因此当“某事完成”时,可以分辨出它是什么以及谁想要它。 IntentService通过将请求记录保存到数据库开始处理:即请求令牌和状态(已启动)。然后它开始处理。处理完成后,它将记录状态更新为“完成”并将结果放在那里。同时,Activity 使用Loader 来收听这张唱片。它根据状态了解它应该在哪种模式下运行。此解决方案适用于所有场景,包括设备方向更改、离开活动、来电等,但感觉就像是奇怪的矫枉过正

我想知道是否有更简单的解决方案。

【问题讨论】:

    标签: android android-intent android-activity intentservice long-running-processes


    【解决方案1】:

    首先,如果您牢记您提到的所有要点,您肯定是在“正确的方向”上。

    您描述的问题很常见,并且大多数应用程序都关心

    你的一些假设有问题:

    活动 + 异步任务。根本不起作用,因为 AsyncTask 绑定到特定的 Activity 实例,并且一旦重新创建 Activity(设备方向更改就是一个例子),AsyncTask 就会绑定到“错误”的上下文。

    没有人说AsyncTask必须从Activity处执行!!

    使用来自android Service 派生类的AsyncTask 也是一个好习惯(不是IntentService..)。这是可能的,因为Service 方法是从主线程执行的。

    实际上,这是我认为的首选解决方案。

    Activity + IntentService。 Activity 触发服务并在 Intent 中提供“请求上下文”。一旦 IntentService 完成,它使用 sendBroadcast() 告诉 Activity 我们在哪里。这不起作用,因为在 IntentService 完成时,Activity 已经暂停,因此它不会收到更新。

    如果活动已经暂停/销毁 - 你没有任何理由更新它!!!!!

    相反,您可以只持久存储此信息/静态单音类,当此活动恢复时 - 它将检索回来,并显示相关状态。

    【讨论】:

    • "如果 Activity 已经销毁" - "paused" 表示"暂停",因此可以恢复 :-)
    • @lok​​i2302:好的,仍然是相同的解决方案 - 检查相同/其他实例何时恢复状态。我已经更新了答案
    猜你喜欢
    • 2013-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-15
    相关资源
    最近更新 更多