有一种常见的应用程序行为模式,即除非完成当前操作,否则无法执行下一步操作。一个很好的例子是身份验证:一旦你向应用程序提供了登录名和密码,并点击"登录",应用程序就会屏蔽一段时间,向你显示一种"等等,我在工作"的指示。尽管这个任务很常见,但我没能在谷歌上找到一个"典型"的解决方案。
我牢记的要点:
-
绝对不能保证"活动"的使用寿命。活动保证在用户启动时启动,但它们可能随时被杀死。因此,一般来说,活动应该被视为交互点,您的应用程序和用户可以在这里讨论他们的"欲望"。总是由用户开始讨论。
-
另一方面,还有服务,这些组件从不直接与用户对话。有的服务寿命保证,所以它似乎是放置处理逻辑的正确位置。
因此,对于我在一开始描述的任务,可以公平地声明:
- 应该有一个登录活动
- 此活动应能够在4种模式下运行:
- 清洁/刚启动/用户尚未按下按钮
- 用户按下按钮,我们正在与web API对话——这是一项长期运行的任务,我们希望显示一种ProgressDialog
- 我们设法与web API进行了交谈,它表示一切正常。在这里,我们可能会完成此活动,并开始更有用的活动-用户在启动应用程序时最初希望看到的活动
- 要么我们没能和网络API对话,要么它说用户凭据有问题。在这种情况下,我们将显示一条错误消息
- 应该有服务负责与网络API对话
所以,这里有一个问题:
如何正确地让"活动"知道当前应激活4种模式中的哪一种
我所考虑的:
-
Activity
+AsyncTask
。根本不起作用,因为AsyncTask
绑定到特定的Activity
实例,并且一旦重新创建Activity
(设备方向更改就是一个例子),AsyncTask
就会绑定到"错误"的上下文。 -
Activity
+IntentService
。活动触发服务并在Intent
中提供"请求上下文"。一旦IntentService
完成,它就使用sendBroadcast()
来告诉Activity
我们在哪里。这不起作用,因为当IntentService
完成时,Activity
已经可以暂停,所以它不会收到更新。 -
与第2页相同,但使用
sendStickyBroadcast()
。这解决了错过更新的问题,但谷歌表示,这是一种糟糕的做法,因为有些开销太大。 -
使用CCD_ 16+
ContentProvider
+CCD_。活动触发服务并在Intent
中提供"请求上下文"。请求上下文有一个神奇的"请求令牌"。该令牌描述了"做某事的独特意图",因此当"做某事"时,可以说出它是什么以及谁想要它。IntentService
通过将请求记录保存到数据库来开始处理:即请求令牌和状态(已启动)。然后它开始处理。处理完成后,它会将记录状态更新为"完成",并将结果放在那里。同时,Activity
使用Loader
来监听该记录。它根据状态了解应该在哪种模式下运行。该解决方案适用于所有场景,包括设备方向更改、离开活动、来电等,但感觉像是奇怪的过度杀戮。
我想知道是否有更简单的解决方案。
首先,如果你考虑到了你提到的所有要点,那么你肯定走在了"正确的方向"上。
您所描述的问题是非常常见的,并且与大多数应用程序有关
你的一些假设有问题:
活动+异步任务。根本不起作用,因为AsyncTask绑定到特定的"活动"实例,并且一旦重新创建"活动"(设备方向更改就是一个例子),AsyncTask就会绑定到"错误"的上下文。
没有人说必须从Activity
执行AsyncTask
!!
使用androidService
派生类中的AsyncTask
(而不是IntentService
.)也是一种很好的做法。这是可能的,因为CCD_ 28方法是从主线程执行的。
事实上,这是我认为的首选解决方案。
Activity+IntentService。活动触发服务并在Intent中提供"请求上下文"。IntentService完成后,它会使用sendBroadcast()告诉活动我们在哪里。这不起作用,因为IntentService完成时,"活动"已经暂停,因此它不会收到更新。
如果活动已经暂停/销毁-您没有任何理由更新它!!!!!
相反,您可以持久地/静态地遍历这个信息singelton类,当这个活动恢复时,它会将其检索回来,并显示相关的状态。