活动开始延迟(startActivity)错误 [英] Activity start is delayed (startActivity) error

查看:175
本文介绍了活动开始延迟(startActivity)错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我已经收到来自信息用户对我的闹钟应用不响时,它应该。最后,其中一个用户具有构建我发信息的日志,这是很奇怪的:

Lately I have been receiving informations from users about my alarm app not ringing when it should. Finally, one of the users have send me information from build in log, that was really strange:

74. 4:25:0 - StartAlarm received
75. 5:22:15 - AlarmOnScreen create
76. 5:22:15 - Time: 04:25

问题是,信息记录保存如下:

Problem is, informations to log are saved as follow:

//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
    (...)

正如你可以看到,活动开始被大大推迟。这怎么可能?用户raported的报警被延迟,直到他开始用手机 - 我想这意味着,直到锁屏没上锁或屏幕开启。我仍然在等待答案更多的信息。在其他时间延迟只有5分钟 - 每一次,直到用户启动使用手机

As you can see, start of the activity was delayed considerably. How is that possible? User raported that alarm was delayed until he started "using" the phone - I guess that means, until lockscreen was unlocked or screen turned on. I am still waiting for answer with more informations. On other time delay was only 5 minutes - every time, until user started "using phone"

任何想法?

编辑:
让我补充一点,就是一些已经开始发生最近,应用是出个月。我仍然在寻找我若也许在表现和最后的更新改变任何东西,但有可能它是财产以后出现这种情况只有在新的Andr​​oid版本?

Let me add, that is something that have started happening lately, after application being out for months. I am still looking if I have maybe changed anything in manifest and in last update, but is it possible that it is somthing that happens only on new Android versions?

推荐答案

我觉得你的问题是关于使用AlarmManager不正确使用WakeLocks,当设备休眠与屏幕处于关闭状态的,你的接收器将不能正常工作。

I think your problem is about using AlarmManager without proper use of WakeLocks, when device "sleeps" with screen turned-off, your receiver will not work properly.

我猜你的接收器得到了AlarmManager的onReceive(),这是最有可能启动时使用 _WAKEUP 标志是这样的:

I guess your receiver got onReceive() from AlarmManager, which is most probably was started with _WAKEUP flag like this:

mAlarmManager.set(AlarmManager.RTC_WAKEUP, .......);

这_WAKEUP标志意味着设备将导通,即使它会在睡眠模式。
然而,正如这里所描述的文件(<一个href=\"http://developer.android.com/reference/android/app/AlarmManager.html\">http://developer.android.com/reference/android/app/AlarmManager.html ):

This _WAKEUP flag means that device will "turn-on" even if it will be in a sleep mode. However, as described by documentation here ( http://developer.android.com/reference/android/app/AlarmManager.html ) :

警报管理器,只要警报接收机的onReceive()方法执行保存在CPU唤醒锁。这可以保证手机不会睡觉,直到你已经处理完播出。一旦的onReceive()返回时,报警管理器释放该唤醒锁。这意味着,在某些情况下,电话将尽快你的onReceive()方法完成睡觉。如果你的报警接收机称为Context.startService(),它是可能的手机会睡请求的服务推出之前。以prevent,你的广播接收器和服务将需要实现一个单独的唤醒锁定策略,以确保手机继续工作,直到服务变得可用。

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.

在您的code,这意味着该系统可以追溯到尽快入睡为的onReceive()结束,如 startActivity(I) 不同步工作 - 这直接导致了上述问题, - 它会推出,但很多很多之后,就当用户打开屏幕

In your code that means that system goes back to sleep as soon as onReceive() ends, and as startActivity(i) doesn't work synchronously - that leads directly to the problem, mentioned above - it will be launched, but much, much later, just when user will turn the screen on.

要解决这个问题,我会建议做这样的事情:

To solve it, I would recommend doing something like this:

//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);
}

这解决方案将首次合作,会让你理解这个问题更深。为了测试 - 刚开始使用时,报警屏幕关闭,可能的话,电缆插入过,但我不知道,如果最后真的需要得到设备进入睡眠模式

This solution will work for the first time and will let you understand the problem deeper. To test - just start to use your alarms when screen is off and, possibly, cable is plugged-off, but I'm not sure if the last is really needed to get device into sleep mode.

不过,我会强烈建议实施更优雅的解决方案,适合你的项目,因为目前的静态参考设计是pretty差,因为它没有在比赛条件完美,例如

However, I would highly recommend to implement more elegant solution, suitable for your project, because current static-reference design is pretty poor, as it doesn't work perfectly in racing conditions, for example.

希望它可以帮助并请让我知道,如果有任何问题。
祝你好运。

Hope it helps and please let me know if any questions. Good luck.

UPD:
我想我还会建议使用不仅PARTIAL_WAKE_LOCK,却充满之一。这样的:

UPD: I think I will also suggest to use not only PARTIAL_WAKE_LOCK, but FULL one. Like:

pm.newWakeLock(PowerManager.FULL_WAKE_LOCK 
    | PowerManager.ACQUIRE_CAUSES_WAKEUP, "providersLock");

这将迫使屏幕为ON,无论如何,不​​依赖于新的活动创造previous状态和平台的反应。

That will force the screen to be ON anyway, not depending on previous state and platform reaction on new activity creation.

这篇关于活动开始延迟(startActivity)错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆