最近,我一直收到用户的信息,说我的闹钟应用程序没有在该响的时候响。最后,其中一位用户从构建日志中向我发送了信息,这真的很奇怪:
74. 4:25:0 - StartAlarm received
75. 5:22:15 - AlarmOnScreen create
76. 5:22:15 - Time: 04:25
问题是,要记录的信息保存如下:
//BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent) {
Logger.initialize(context);
Logger.log("StartAlarm received");
Intent i = new Intent(context, AlarmOnScreen.class);
i.putExtras(intent.getExtras());
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
//AlarmOnScreen (activity)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm_on_screen);
Logger.log("AlarmOnScreen create");
//Time value of alarm is logged below
(...)
如您所见, Activity 的开始时间大大延迟了。这怎么可能?用户报告说,直到他开始“使用”手机时,警报才被延迟——我想这意味着,直到锁屏被解锁或屏幕被打开。我仍在等待更多信息的答案。在其他时间延迟只有 5 分钟 - 每次,直到用户开始“使用电话”
有什么想法吗?
编辑: 让我补充一下,这是最近开始发生的事情,在申请发布几个月后。我仍在查看我是否在 list 和上次更新中更改了任何内容,但是否有可能只在新的 Android 版本上发生?
最佳答案
我认为您的问题是在没有正确使用 WakeLocks 的情况下使用 AlarmManager,当设备在屏幕关闭的情况下“休眠”时,您的接收器将无法正常工作。
我猜你的接收器从 AlarmManager 获得了 onReceive(),这很可能是从 _WAKEUP
标志开始的,如下所示:
mAlarmManager.set(AlarmManager.RTC_WAKEUP, .......);
这个 _WAKEUP 标志意味着设备将“打开”,即使它处于 sleep 模式。 但是,如此处的文档所述 (http://developer.android.com/reference/android/app/AlarmManager.html):
The Alarm Manager holds a CPU wake lock as long as the alarm receiver's onReceive() method is executing. This guarantees that the phone will not sleep until you have finished handling the broadcast. Once onReceive() returns, the Alarm Manager releases this wake lock. This means that the phone will in some cases sleep as soon as your onReceive() method completes. If your alarm receiver called Context.startService(), it is possible that the phone will sleep before the requested service is launched. To prevent this, your BroadcastReceiver and Service will need to implement a separate wake lock policy to ensure that the phone continues running until the service becomes available.
在您的代码中,这意味着系统会在 onReceive()
结束后立即返回 sleep 状态,并且 startActivity(i)
不会同步工作 - 这会导致直接针对上面提到的问题 - 它会启动,但是要晚很多很多,就在用户打开屏幕的时候。
要解决这个问题,我建议您这样做:
//BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent) {
Logger.initialize(context);
Logger.log("StartAlarm received");
Intent i = new Intent(context, AlarmOnScreen.class);
i.putExtras(intent.getExtras());
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
AlarmOnScreen.acquireLock(context);
//Before, system could sleep right after this line(not exactly, however) and activity actually would be started much later
}
//AlarmOnScreen (activity)
private static WakeLock sWakeLock;
public static void acquireLock(Context context) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "providersLock");
//Limit 10 sec, if something wrong will happen - we'll not drain the battery to much.
sWakeLock.acquire(10000);
//As we are acquiring and releasing only once - we don't need a counter.
sWakeLock.setReferenceCounted(false);
}
private static void releaseLock(Context context) {
try {
sWakeLock.release();
} catch (Exception e) {
//In case it's already auto-released
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm_on_screen);
Logger.log("AlarmOnScreen create");
//Time value of alarm is logged below
(...)
@Override
protected void onResume() {
releaseLock(this);
}
这个解决方案将第一次起作用,会让你更深入地理解问题。测试 - 只需在屏幕关闭时开始使用您的闹钟,并且可能会断开电缆,但我不确定是否真的需要最后一个才能让设备进入休眠模式。
但是,我强烈建议实现更优雅的解决方案,适合您的项目,因为当前的静态引用设计非常糟糕,例如,它在赛车条件下无法完美运行。
希望对您有所帮助,如有任何问题,请告诉我。 祝你好运。
更新: 我想我还会建议不仅使用 PARTIAL_WAKE_LOCK,还建议使用 FULL。喜欢:
pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP, "providersLock");
无论如何,这将强制屏幕打开,而不取决于之前的状态和平台对新 Activity 创建的 react 。
关于android - Activity 启动延迟(startActivity)错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12314122/