[英]WakeLock with PARTIAL_WAKE_LOCK is not working
I have an alarm application and was contacted by the user which reported that his alarms are sometimes delayed.我有一个警报应用程序,用户联系了我,报告说他的警报有时会延迟。 I have tried different approaches and theories and finally suggested the user to use default Android's alarm as a backup.
我尝试了不同的方法和理论,最后建议用户使用默认的Android警报作为备份。
Usually alarms were delayed by about an hour, but last time my alarm has started just after Android's one - clear suggestion, that device was asleep and got awoken with Android's alarm, allowing for mine to "continue starting" as well.通常闹钟会延迟大约一个小时,但上次我的闹钟是在 Android 的一个明确建议之后启动的,该设备处于睡眠状态并被 Android 的闹钟唤醒,让我的设备也可以“继续启动”。
Edit: As I have modified some classes and have already received log from new version, I am changing classes and log information below.编辑:由于我修改了一些类并且已经收到来自新版本的日志,我正在更改下面的类和日志信息。
Here's the CountedWakeLock class I am using - I created my own HandlerThread to handle delayed releasing of the wake lock, in order to check if that can affect problems with start.这是我正在使用的 CountedWakeLock 类 - 我创建了自己的 HandlerThread 来处理唤醒锁的延迟释放,以检查这是否会影响启动问题。 It did not fix the problem, but it has produced interesting information in the log (below).
它没有解决问题,但它在日志中产生了有趣的信息(如下)。
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 BroadcastReceiver - it is receiving intents from AlarmManager AlarmReceiver BroadcastReceiver - 它正在从 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.启动警报接收器。 It is actually starting the 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");
}
Updated log:更新日志:
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...
From the log now I believe that WakeLock is actually working - after all CPU must have been running, if TimeoutReleaseThread was able to finish working.从现在的日志中,我相信 WakeLock 确实在工作 - 毕竟 CPU 必须一直在运行,如果 TimeoutReleaseThread 能够完成工作。
Question is why AlarmOnScreen Activity was not started??问题是为什么 AlarmOnScreen Activity 没有启动? And why Main Activity (lines 511-514) has started?
为什么 Main Activity(第 511-514 行)已经开始? Recently I have made AlarmOnScreen have singleTask mode set in manifest.
最近我让 AlarmOnScreen 在清单中设置了单任务模式。 Could that be causing the problem?
这可能是导致问题的原因吗? But why?
但为什么? I need this singleTask for few other reasons...
由于其他几个原因,我需要这个 singleTask ......
Device is GT-S5830i with 2.3.6 Android.设备为 GT-S5830i,Android 2.3.6。
I still have no idea what caused the problem, but if anyone will ever experience similar one - after many tests, it was only one simple change - adding Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED to Intent in StartAlarmReceiver.我仍然不知道是什么导致了这个问题,但如果有人会遇到类似的问题——经过多次测试,这只是一个简单的改变——在 StartAlarmReceiver 中将 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 添加到 Intent。
So it's like所以就像
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
Does it work?它有效吗? Yes, it does.
是的,它确实。 And so far it didn't cause any problems on other phones.
到目前为止,它没有在其他手机上造成任何问题。
Does it make sense?是否有意义? No, not at all.
一点都不。
我通过这种方式发送通知解决了我的服务问题:
startForeground(ID, notification)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.