我的活动启动了一个运行CountDownTimer的服务。计时器在倒计时时将广播发送回活动。活动处理BroadcastReceiver的onReceive方法中的广播。所有这一切都很好。
当按以下顺序发生以下事件时,我的问题出现了:
当应用程序恢复时,服务不再发送广播,因此活动不知道计时器剩余多少时间或完成时间。这可以防止活动更新UI。
我已经尝试了十几种处理方法,并阅读了许多Stack Overflow问题和答案,但我还没有找到解决方案。我认为有一种方法可以获取在活动未激活时发送的广播,但我还没找到方法。
对于记录,这是我的相关活动和服务代码:
activity.java
// Start service
timerIntent.putExtra("totalLength", totalLength);
this.startService(timerIntent);
// ...
// BroadcastReceiver
private BroadcastReceiver br = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getExtras() != null && inSession) {
session.setRemaining(intent.getExtras().getLong("millisUntilFinished"));
updateProgress();
}
}
};
// ...
// onResume
@Override
public void onResume() {
super.onResume();
registerReceiver(br, new IntentFilter(TimerService.COUNTDOWN_TS));
}
service.java
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
long length = intent.getExtras().getLong("totalLength");
countDownTimer = new CountDownTimer(length, 1000) {
@Override
public void onTick(long millisUntilFinished) {
timerServiceIntent.putExtra("millisUntilFinished", millisUntilFinished);
sendBroadcast(timerServiceIntent);
}
@Override
public void onFinish() {
}
};
countDownTimer.start();
return super.onStartCommand(intent, flags, startId);
}
处理活动停止时服务发送的广播的最佳方式是什么?
答案 0 :(得分:3)
使用BroadcastReceiver存储它收到的最后一个请求(可能是SharedPreferences),并在Activity启动时检查它。
或者,不是使用广播处理倒计时,而是存储倒计时结束的时间。然后,Activity可以自动处理倒计时,因为它知道它应该何时结束。对于这样一个简单的任务,使用服务和广播似乎有点过度设计。
更新: 从你描述任务的方式来看,我发现你需要处理2个场景。这就是我可能会这样做的。
假设“XYZ”是服务\ intent \无论什么开始倒计时,“ABC”是显示进度的活动。 (ABC和XYZ可能是相同的活动,如果这是你想要的)
要求: 当倒计时开始时,我会让XYZ存储倒计时应该在SharedPreferences中结束的时间。
ABC在倒计时开始时已经在运行。正如Commonsware所说,只要XYZ和ABC在同一个过程中运行,Eventbus模型就非常适合处理这种情况。只需触发事件即可读取首选项值并倒计时到指定时间。如果用户关闭ABC并重新打开它,则方案2将启动。
ABC未运行。检查OnResume是否已经过倒数时间。如果没有,请设置ABC以再次显示倒计时。如果没有倒计时,请执行其他操作。
如果您在倒计时已经过去时也需要做某事,无论您是否有活动的UI,那么Commonsware对AlarmManager的建议也是完美的。
答案 1 :(得分:1)
让我们暂时假装使用Service
和CountDownTimer
跟踪某段时间以更新Activity
实际上是一个好主意。这不是不可能的,假设Service
实际上正在做一些真实的事情,而这个时机是一些副产品。
活动在停止时不接收广播,主要是出于性能/电池原因。相反,活动需要在启动时拉入当前状态,然后使用事件(例如,您当前的广播)在数据启动时通知数据的变化。
这可以通过使用greenrobot的EventBus及其粘性事件来简化,因为活动会在订阅获取事件时自动获取最后一个事件。为此目的使用greenrobot的EventBus还可以减少您通过使用系统广播在同一进程中在两个Java类之间进行通信而引入的安全性和性能问题。
另外,请坚持生命周期对。 onResume()
不是onStop()
的对应物。 onStart()
与onStop()
相对应; onResume()
与onPause()
相对应。在一对中初始化某些内容(例如onResume()
)并在另一对中清除它(例如,onStop()
)会冒双重初始化或双重清理错误的风险。
答案 2 :(得分:1)
处理服务发送的广播的最佳方式是什么 活动停止了吗?
使用来自服务的粘性广播意图,然后从活动中检索它们将是一种处理服务在活动停止时发送的广播的方法。我只能提供这个可能的解决方案,而不是声称它是最好的方式"。
但是,出于安全考虑,他们已经因API级别21而被弃用。答案 3 :(得分:0)
您可以使用有序广播(使用Context.sendOrderedBroadcast发送),而不是使用普通广播。为此,在活动中定义BroadcastReceiver时,您需要在清单中使用相同的intentfilter定义BroadcastReceiver。只有更改是在您的活动中注册BroadcastReceiver时需要将优先级设置为高,这样当您的活动正在运行并且活动的BroadcastReceiver被注册时,它首先被调用,并且在此BroadcastReceive的onReceive中,您可以使用abortBroadcast获取被调用的BroadcastReceiver在你的android清单中定义。现在,当您的活动未运行时,您的Android清单中定义的BroadcastReceiver将被调用。因此,这样您就可以获得状态,如果您希望通过通知显示用户的更新,即使您的活动没有运行。