PARTIAL_WAKE_LOCK的WakeLock无法正常工作

3
我有一个闹钟应用程序,有一位用户向我报告他的闹钟有时会延迟。我尝试了不同的方法和理论,最终建议用户将默认的安卓闹钟作为备用。

通常情况下,闹钟会延迟约一个小时,但上次我的闹钟刚好在安卓闹钟之后启动 - 这清楚地表明设备处于睡眠状态,并通过安卓闹钟唤醒,使得我的闹钟也能够“继续启动”。

编辑: 由于我修改了一些类并已经收到新版本的日志,因此我正在更改以下类和日志信息。

这是我使用的CountedWakeLock类 - 我创建了自己的HandlerThread来处理延迟释放唤醒锁的问题,以检查它是否会影响启动问题。它没有解决问题,但在日志中产生了有趣的信息(如下)。
public class CountedWakeLock {

private static long TIMEOUT_DEFAULT =  DateUtils.MINUTE_IN_MILLIS * 3;
private static WakeLock sWakeLock = null;
private static int sLockCount;

private static class TimeoutReleaseThread extends HandlerThread {

    static TimeoutReleaseThread mInstance = null;

    Handler mHandler;
    private Runnable mReleaseRunnable;

    public static TimeoutReleaseThread instance() {
        if (mInstance == null) mInstance = new TimeoutReleaseThread();
        return mInstance;
    }

    public TimeoutReleaseThread() {
        super("TimeoutReleaseThread HandlerThread");
        start();
        mHandler = createHandler();
        mReleaseRunnable = new Runnable() {

            @Override
            public void run() {
                Utils.log("TimeoutReleaseThread release lock");
                releaseLock();
            }
        };
    }

    private synchronized Handler createHandler() {
        return new Handler(getLooper());
    }

    public synchronized void postRelease(long timeout) {
        mHandler.removeCallbacks(mReleaseRunnable);
        mHandler.postDelayed(mReleaseRunnable, timeout);
    }
}

public synchronized static void acquireLock(Context context) {
    acquireLock(context, TIMEOUT_DEFAULT);
}

public synchronized static void acquireLock(Context context, long timeout) {
    if (sWakeLock == null) {
        Utils.log("WakeLock creating");
        PowerManager pm = (PowerManager) context.getApplicationContext()
                .getSystemService(Context.POWER_SERVICE);
        sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                "AlarmReceiver lock");
        sWakeLock.setReferenceCounted(false);
        sLockCount = 0;
    } else if (sWakeLock.isHeld())
        Utils.log("WakeLock held already");
    else
        Utils.log("WakeLock not held");

    Utils.log("WakeLock acquiring for " + timeout);
    sLockCount++;
    sWakeLock.acquire();
    TimeoutReleaseThread.instance().postRelease(timeout);
}

public synchronized static void releaseLock() {
    Utils.log("WakeLock releasing");
    if (sWakeLock == null) {
        Utils.log("WakeLock==null");
    } else if (!sWakeLock.isHeld()) {
        Utils.log("WakeLock not held");
        sWakeLock = null;
        sLockCount = 0;
    } else {
        sLockCount--;
        if (sLockCount <= 0) {
            Utils.log("WakeLock released");
            sWakeLock.release();
            sWakeLock = null;
            if (sLockCount != 0) Utils.log("lockcount=" + sLockCount);

        }
    }
}
}

AlarmReceiver广播接收器 - 它从AlarmManager接收意图

public void onReceive(Context context, Intent intent) {
    Logger.initialize(context, "AlarmReceiver");
    if (CALL_IS_ON) {
        //set another alarm with AlarmManager to start after 5 seconds
        //doesn't happen in this situation
    } else {
        Utils.log("sending START ALARM");
        CountedWakeLock.acquireLock(context);
        Intent i = new Intent();
        i.setAction(StartAlarmReceiver.ACTION_START_ALARM);
        i.putExtras(intent.getExtras());

        context.sendOrderedBroadcast(i, null); //it is ordered, so eventual previous Alarm Activities etc. can be stopped
        Utils.log("START ALARM send");
    }
}

StartAlarmReceiver。它实际上是启动闹钟活动(Alarm Activity)。

public void onReceive(Context context, Intent intent) {
    Logger.initialize(context, "StartAlarmReceiver");
    Intent i = new Intent(context, AlarmOnScreen.class);
    Bundle extras = intent.getExtras();
    i.putExtras(extras);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(i);
    Utils.log("AlarmActivity started");
}

更新日志:

504. 27/3 5:0:0 - logger initialized again from AlarmReceiver
505. 27/3 5:0:0 - sending START ALARM
506. 27/3 5:0:0 - WakeLock creating
507. 27/3 5:0:0 - WakeLock acquiring for 180000
508. 27/3 5:0:0 - START ALARM send
509. 27/3 5:0:0 - logger initialized again from StartAlarmReceiver
510. 27/3 5:0:0 - AlarmActivity started
511. 27/3 5:0:0 - Main start
512. 27/3 5:0:1 - Main resume
513. 27/3 5:0:1 - Main pause
514. 27/3 5:0:5 - Main stop
515. 27/3 5:3:0 - TimeoutReleaseThread release lock
516. 27/3 5:3:0 - WakeLock releasing
517. 27/3 5:3:0 - WakeLock released
518. 27/3 6:46:18 - logger initialized again from AlarmOnScreen create //user said he unlocked phone then to check the time...

从日志中我相信WakeLock实际上是起作用的-毕竟如果TimeoutReleaseThread能够完成工作,CPU必须一直在运行。

问题是为什么AlarmOnScreen Activity没有启动?而为什么Main Activity(第511-514行)已经启动了?最近我在清单文件中设置了AlarmOnScreen的singleTask模式。这可能会引起问题吗?但为什么?我需要这个singleTask来满足其他一些需求...

设备是带有2.3.6 Android的GT-S5830i。

2个回答

2

我仍然不知道问题的原因,但如果有人遇到类似的问题 - 经过多次测试,只需要进行一个简单的更改 - 在StartAlarmReceiver中的Intent中添加Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED。

就像这样

i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
     | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

它有效吗?是的,它有效。到目前为止,它没有在其他手机上引起任何问题。

它有意义吗?不,一点也不。


我有完全相同的问题 - 一个启动活动的服务,在启动活动之前有一个唤醒锁。有时候活动就是不会启动,看起来是随机的,所以我首先寻找了唤醒锁的问题,但没有成功。如果这个标志真的是解决方案,那么你就为我省了很多工作。干得好!我无法重现我的问题,所以我只能使用这段代码并观察发生了什么。如果它解决了问题,那么我欠你一个大人情。我会尝试回来给这个答案一个赏金。如果我忘记了,请提醒我。 - Stephen Hosking
请问您能否解释一下在哪里使用这些标志,因为在我的情况下,闹钟在设备重新启动后仍然无法工作,尽管我已经实现了boot_completed接收器。 - Mayank Kumar Chaudhari

2
我通过以下方式发送通知,解决了我的问题:

使用服务来发送通知。

startForeground(ID, notification)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接