我认为您的问题是在没有正确使用 WakeLocks 的情况下使用 AlarmManager,当设备在屏幕关闭的情况下“休眠”时,您的接收器将无法正常工作。
我猜你的接收器从 AlarmManager 得到了 onReceive(),这很可能是用_WAKEUP
这样的标志开始的:
mAlarmManager.set(AlarmManager.RTC_WAKEUP, .......);
这个 _WAKEUP 标志意味着设备将“开启”,即使它处于睡眠模式。但是,如此处的文档所述(http://developer.android.com/reference/android/app/AlarmManager.html):
只要警报接收器的 onReceive() 方法正在执行,警报管理器就会持有 CPU 唤醒锁。这保证了在您完成广播处理之前手机不会休眠。一旦 onReceive() 返回,警报管理器就会释放这个唤醒锁。这意味着在某些情况下,一旦您的 onReceive() 方法完成,手机就会进入睡眠状态。如果您的警报接收器调用了 Context.startService(),则手机可能会在请求的服务启动之前休眠。为防止这种情况,您的 BroadcastReceiver 和 Service 将需要实施单独的唤醒锁定策略,以确保手机继续运行直到服务可用。
在您的代码中,这意味着系统一旦onReceive()
结束就会重新进入睡眠状态,并且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);
}
该解决方案将首次起作用,让您更深入地了解问题。进行测试 - 只需在屏幕关闭时开始使用您的闹钟,并且可能会拔掉电缆,但我不确定最后一个是否真的需要让设备进入睡眠模式。
但是,我强烈建议实施更优雅的解决方案,适合您的项目,因为当前的静态参考设计很差,例如,它在赛车条件下无法完美运行。
希望它有所帮助,如果有任何问题,请告诉我。祝你好运。
UPD:
我想我还建议不仅使用 PARTIAL_WAKE_LOCK,而且还使用 FULL 一个。喜欢:
pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP, "providersLock");
无论如何,这将强制屏幕打开,而不取决于先前的状态和平台对新活动创建的反应。