我们正在尝试在android中实现本机代码的计时器。计时器应该在唤醒和睡眠模式下正常工作。当计时器到期时,我们的本机代码将向网络发送DPD(死对等检测)消息我们尝试了以下方法。
3.使用唤醒锁*我们试图避免使用唤醒锁,因为它可能会导致严重的性能问题
PS - 开源Ipsec实现strongswan即使在睡眠模式下也会发送DPD消息的精确时间。但似乎strongswan不使用唤醒锁定,所以我们仍然试图弄清楚它在睡眠模式下的工作原理。任何人都在寻找答案问题可能想要查看该代码。
任何人都可以建议一些方法来解决这个问题。
当Android进入睡眠状态时,它会有几种状态,最后一种状态是冻结所有进程并关闭CPU。在那种情况下,你的时间不会被激发。您必须创建一个唤醒内核并设置唤醒锁定的事件,以便cpu不会再次关闭。这可以使用android报警来完成。
使计时器在睡眠模式下正常工作的唯一方法是使用Wakelock保持设备部分清醒。但请确保您的应用程序确实需要计时器一直工作,因为文档说,
使用此API会严重影响设备电池寿命。除非确实需要,否则不要获得PowerManager.WakeLocks,尽可能使用最低级别,并确保尽快释放它们。
通过PowerManager类,使用下面的代码获取部分唤醒锁
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
..cpu will stay on during this section..
wl.release();
启动计时器,当应用程序进入后台时,启动alarmManager。再次,如果应用程序来到前台并且计时器未到期,那么它将重新触发计时器并将删除警报管理器。
private int timeToStart;
private TimerState timerState;
private static final int MAX_TIME = 60; //Time length is 60 seconds
private enum TimerState {
STOPPED,
RUNNING
}
private void initTimer() {
Log.e(TAG,"initTimer called");
long startTime = mPrefs.getStartedTime(); //here mprefs is your shared preference manager
if (startTime > 0) {
timeToStart = (int) (MAX_TIME - (getNow() - startTime));
if (timeToStart <= 0) {
// TIMER EXPIRED
onTimerFinish();
} else {
startTimer();
timerState = TimerState.RUNNING;
}
} else {
timeToStart = MAX_TIME;
timerState = TimerState.STOPPED;
}
}
private long getNow() {
Calendar rightNow = Calendar.getInstance();
return rightNow.getTimeInMillis() / 1000;
}
private void onTimerFinish() {
Log.e(TAG,"onTimerFinish() called");
timerState = TimerState.STOPPED;
mPrefs.setStartedTime(0);
timeToStart = MAX_TIME;
}
private void startTimer() {
Log.e(TAG,"startTimer() called");
countDownTimer = new CountDownTimer(timeToStart * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
timeToStart -= 1;
}
@Override
public void onFinish() {
onTimerFinish();
}
}.start();
}
public void setAlarmManager() {
int wakeUpTime = (mPrefs.getStartedTime() + MAX_TIME) * 1000;
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, TimeReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
am.setAlarmClock(new AlarmManager.AlarmClockInfo(wakeUpTime, sender), sender);
} else {
am.set(AlarmManager.RTC_WAKEUP, wakeUpTime, sender);
}
}
public void removeAlarmManager() {
Intent intent = new Intent(this, TimeReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.cancel(sender);
}
@Override
protected void onResume() {
super.onResume();
initTimer();
removeAlarmManager();
}