android - Activity 启动延迟(startActivity)错误

标签 android

最近,我一直收到用户的信息,说我的闹钟应用程序没有在该响的时候响。最后,其中一位用户从构建日志中向我发送了信息,这真的很奇怪:

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/

相关文章:

使用 ANT 脚本构建 Android NDK

java - Android SQLite 游标错误

android - 如何获取 UTC 中的时区偏移量(如 UTC+07 :00) from a physical device?

android - 应用程序 apk 大小超过 100mb。如何上传到 PlayStore?

android - 如果应用程序未至少启动一次,则广播接收器无法在 ICS 中工作

java - react native - MainActivity.java

Java - 当子线程因 NPE 死亡时会发生什么,父线程是否会被杀死

java - 如何通过传递 json URL 使 URL 中的空格可读

android - 在 xml 错误中添加自定义组件

android - Android 中是否有针对 "users blocking our notifications"的 API?