Android AlarmManager 在 phone 睡眠时不工作
Android AlarmManager not working while phone asleep
AlarmManager 有问题。
总之,我计划一个alarmManager :
Intent intent = new Intent(context, MyActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delayInMs, pendingIntent);
并且 activity MyActivity 在指定时间出现。就在设备插入时。当它在我的口袋里,或者延迟几分钟时,它也能工作。
但是当我在晚上之前设置 alarmManager 时,它不会在早上工作。但是,只要我拿phone或解锁屏幕,它就会起作用。
所以,我想这是由于设备的睡眠模式,但如何解决这个问题?
1) 我在 myActivity 的每个方法中都添加了一个日志,我确定在我手动唤醒设备之前没有人被调用。
2) 我尝试了 PowerManagement 的唤醒锁(使用清单中的 WAKE_LOCK 权限),但没有任何改变:
alarmManager.setExact(.........);
wakeLock = ((PowerManager)contexte.getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, "MyActivity");
wakeLock.acquire();
请帮忙!我确定我很接近...
编辑 2016 年 12 月 4 日:
感谢 Nick Friskel 和 Vikram Rao,我更改了初始代码以调用 broadcastReceiver 并在 onReceive 中获取我的唤醒锁。不幸的是,它似乎不起作用。当插入 phone 或计划在 35 分钟后发出警报时,它可以完美地工作,但在整个晚上,甚至都没有调用 onReceive。
我那天晚上尝试过,计划在 9:00 AM 发出警报,但 onReceive 仅在 9:46 AM 执行,这意味着我解锁设备的那一刻。
这是我的新代码:
Intent intent = new Intent("com.blah.something.ALARM_RECEIVED");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delayInMs, pendingIntent);
就是说,出于某种原因,我写的日志 "start of onReceive" 并不是真的在侦听器的开头。刚好放在real的开头,看看有没有调用listener。
编辑 2016 年 12 月 5 日:
因此,我更改了 onReceive 顶部的日志写入,并发生了同样的问题:一旦我手动唤醒设备,就会调用 onReceive 的开始。
我可以实现 wakefulBroadcastReceiver,但我担心它不会解决任何问题。如果我理解正确,wakefulBroadcastReceiver 可用于防止设备在 onReceive 和 activity 或服务启动之间休眠。但是,如果甚至没有调用 onReceive 怎么办?
我有点绝望……也许我应该直接问索尼。
此外,我的 phone 有耐力模式,但没有激活。
编辑 2016 年 12 月 11 日:
因此,通过更多测试,我现在确定我什么都不懂……我设置了一个每 5 分钟激活一次的 broadcastReceiver(onReceive 在 5 分钟后重置 alarmManager),我可以看到它工作正常……有时.它可以持续几个小时,然后睡两个小时,然后 30 分钟就可以了,然后再睡。 (当我的 phone 打开、拔下电源并闲置时,所有这些)。
我将删除所有我们感兴趣的代码。它会更容易理解,我将能够在这里编写所有活动代码。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.par.hasard.mysimpleapplication">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.par.hasard.mysimpleapplication.MySimpleReceiver">
<intent-filter android:priority="1">
<action android:name="com.par.hasard.mysimpleapplication.REGULAR_ALARM" />
</intent-filter>
</receiver>
</application>
</manifest>
MainActivity.java
package com.par.hasard.mysimpleapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.myExportButton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MyLogManager.copyLogToClipboard(view.getContext());
MyLogManager.emptyLogFile(view.getContext());
}
});
try {
MyLogManager.createLogFile(this);
MyLogManager.write(this, "Application launched\n");
MyAlarmPlanner.planAlarm(this);
} catch (Exception e) {
e.printStackTrace();
}
}
}
MySimpleReceiver.java
package com.par.hasard.mysimpleapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MySimpleReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
MyLogManager.write(context, "Beginning of onReceive\n");
MyAlarmPlanner.planAlarm(context);
MyLogManager.write(context, "End of onReceive\n");
} catch (Exception e) {
e.printStackTrace();
}
}
}
MyAlarmPlanner.java
package com.par.hasard.mysimpleapplication;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import java.io.IOException;
public class MyAlarmPlanner {
public static void planAlarm(Context context) throws IOException {
MyLogManager.write(context, "Beginning of alarm planning\n");
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent("com.par.hasard.mysimpleapplication.REGULAR_ALARM");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.cancel(pendingIntent);
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 300000, pendingIntent);
MyLogManager.write(context, "End of alarm planning\n");
}
}
我觉得MyLogManager.java没什么用,就是无聊的文件管理方法。
长时间空闲后的日志文件内容:
12/12 15h33m23s380 => Beginning of onReceive
12/12 15h33m23s381 => Beginning of alarm planning
12/12 15h33m23s383 => End of alarm planning
12/12 15h33m23s384 => End of onReceive
12/12 15h38m24s337 => Beginning of onReceive
12/12 15h38m24s339 => Beginning of alarm planning
12/12 15h38m24s375 => End of alarm planning
12/12 15h38m24s376 => End of onReceive
12/12 15h43m24s375 => Beginning of onReceive
12/12 15h43m24s376 => Beginning of alarm planning
12/12 15h43m24s380 => End of alarm planning
12/12 15h43m24s381 => End of onReceive
12/12 15h48m25s301 => Beginning of onReceive
12/12 15h48m25s304 => Beginning of alarm planning
12/12 15h48m25s307 => End of alarm planning
12/12 15h48m25s308 => End of onReceive
12/12 15h53m25s316 => Beginning of onReceive
12/12 15h53m25s318 => Beginning of alarm planning
12/12 15h53m25s328 => End of alarm planning
12/12 15h53m25s329 => End of onReceive
12/12 15h58m25s328 => Beginning of onReceive
12/12 15h58m25s329 => Beginning of alarm planning
12/12 15h58m25s331 => End of alarm planning
12/12 15h58m25s333 => End of onReceive
12/12 16h3m26s336 => Beginning of onReceive
12/12 16h3m26s351 => Beginning of alarm planning
12/12 16h3m26s379 => End of alarm planning
12/12 16h3m26s380 => End of onReceive
12/12 16h8m26s397 => Beginning of onReceive
12/12 16h8m26s401 => Beginning of alarm planning
12/12 16h8m26s404 => End of alarm planning
12/12 16h8m26s405 => End of onReceive
12/12 16h13m26s406 => Beginning of onReceive
12/12 16h13m26s407 => Beginning of alarm planning
12/12 16h13m26s410 => End of alarm planning
12/12 16h13m26s411 => End of onReceive
12/12 16h18m27s328 => Beginning of onReceive
12/12 16h18m27s329 => Beginning of alarm planning
12/12 16h18m27s346 => End of alarm planning
12/12 16h18m27s348 => End of onReceive
12/12 16h23m28s298 => Beginning of onReceive
12/12 16h23m28s299 => Beginning of alarm planning
12/12 16h23m28s303 => End of alarm planning
12/12 16h23m28s304 => End of onReceive
12/12 16h28m29s308 => Beginning of onReceive
12/12 16h28m29s310 => Beginning of alarm planning
12/12 16h28m29s323 => End of alarm planning
12/12 16h28m29s324 => End of onReceive
12/12 16h33m29s339 => Beginning of onReceive
12/12 16h33m29s340 => Beginning of alarm planning
12/12 16h33m29s355 => End of alarm planning
12/12 16h33m29s361 => End of onReceive
12/12 16h38m29s356 => Beginning of onReceive
12/12 16h38m29s357 => Beginning of alarm planning
12/12 16h38m29s360 => End of alarm planning
12/12 16h38m29s361 => End of onReceive
12/12 16h43m29s364 => Beginning of onReceive
12/12 16h43m29s365 => Beginning of alarm planning
12/12 16h43m29s367 => End of alarm planning
12/12 16h43m29s369 => End of onReceive
12/12 16h48m29s376 => Beginning of onReceive
12/12 16h48m29s380 => Beginning of alarm planning
12/12 16h48m29s390 => End of alarm planning
12/12 16h48m29s394 => End of onReceive
12/12 16h53m29s392 => Beginning of onReceive
12/12 16h53m29s394 => Beginning of alarm planning
12/12 16h53m29s402 => End of alarm planning
12/12 16h53m29s403 => End of onReceive
12/12 17h43m33s986 => Beginning of onReceive //problem, the 16'58 onReceive wasn't called
12/12 17h43m33s988 => Beginning of alarm planning
12/12 17h43m33s996 => End of alarm planning
12/12 17h43m34s4 => End of onReceive
12/12 17h48m34s535 => Beginning of onReceive
12/12 17h48m34s536 => Beginning of alarm planning
12/12 17h48m34s539 => End of alarm planning
12/12 17h48m34s540 => End of onReceive
12/12 18h29m49s635 => Beginning of onReceive //the moment I turned on my device
12/12 18h29m49s648 => Beginning of alarm planning
12/12 18h29m49s667 => End of alarm planning
12/12 18h29m49s668 => End of onReceive
谁能告诉我我的错误在哪里?
执行此操作的正确方法是让您的 AlarmManager 触发 BroadcastReceiver 而不是直接 Activity。然后,您可以将唤醒锁放在广播接收器 class 内,然后 运行 您的 activity 来自 BroadcastReceiver 或来自从 BroadcastReceiver 启动的 IntentService。
您的意图将更改为:
Intent intent = new Intent(context, MyActivityReceiver.class);
然后制作你的广播接收器:
package com.yourpackage (change this to your package)
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyActivityReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 0; //only necessary if you have more receivers
// when the alarm is triggered
@Override
public void onReceive(Context context, Intent intent) {
wakeLock = ((PowerManager)contexte.getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, "MyActivity");
wakeLock.acquire();
Intent i = new Intent(context, MyActivity.class);
context.startService(i);
}
}
并将收件人添加到您的清单中:
<receiver
android:name="service.TimeService"
android:enabled="true"
android:exported="false"
>
</receiver>
如果这不起作用,那么您需要通过 WakefulService 启动 activity。
android 中的 AlarmManager api 有其局限性。对于 -
- 它在设备重启时被清除(所有警报丢失)
- 在设备 lock/sleep 状态 lock/sleep 期间,其行为在制造商和 android 版本之间不一致
我解决这些问题的方法是 -
- 创建具有广播意图的警报,然后将侦听器添加到该广播以执行必要的操作。
像这样-
Intent intent = new Intent("com.blah.something.ALARM_RECIEVED");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Html5Activity.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, triggerTimeInMillis, pendingIntent);
清单文件 -
<receiver android:name=".receiver.BackgroundScheduledAlarmReceiver">
<intent-filter android:priority="1">
<action android:name="com.blah.something.ALARM_RECIEVED" />
</intent-filter>
</receiver>
- 将警报保存在 sqlite 或其他地方(此处未显示)并在设备重启时通过像这样侦听设备启动来重新创建它们 -
清单文件 -
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<receiver
android:name=".receiver.RecreateAlarmsAtBootReceiver"
android:enabled="true"
android:exported="true"
android:label="RecreateAlarmsAtBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
在RecreateAlarmsAtBootReceiver
中,读取存储报警的sqlite,重新添加到报警管理器中。
感谢CommonsWare,问题解决了!此失败是由于打瞌睡模式 (https://developer.android.com/training/monitoring-device-state/doze-standby.html)
简而言之,自 Android 6.0 起,AlarmManager 会受到影响,并且如果设备处于此休眠模式则无法触发。但是您可以将 setExact 替换为 setExactAndAllowWhileIdle。有局限性,但我们必须应对。 CommonsWare 回答了 link 到 post 的问题:
AlarmManager 有问题。
总之,我计划一个alarmManager :
Intent intent = new Intent(context, MyActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delayInMs, pendingIntent);
并且 activity MyActivity 在指定时间出现。就在设备插入时。当它在我的口袋里,或者延迟几分钟时,它也能工作。 但是当我在晚上之前设置 alarmManager 时,它不会在早上工作。但是,只要我拿phone或解锁屏幕,它就会起作用。
所以,我想这是由于设备的睡眠模式,但如何解决这个问题?
1) 我在 myActivity 的每个方法中都添加了一个日志,我确定在我手动唤醒设备之前没有人被调用。 2) 我尝试了 PowerManagement 的唤醒锁(使用清单中的 WAKE_LOCK 权限),但没有任何改变:
alarmManager.setExact(.........);
wakeLock = ((PowerManager)contexte.getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, "MyActivity");
wakeLock.acquire();
请帮忙!我确定我很接近...
编辑 2016 年 12 月 4 日: 感谢 Nick Friskel 和 Vikram Rao,我更改了初始代码以调用 broadcastReceiver 并在 onReceive 中获取我的唤醒锁。不幸的是,它似乎不起作用。当插入 phone 或计划在 35 分钟后发出警报时,它可以完美地工作,但在整个晚上,甚至都没有调用 onReceive。 我那天晚上尝试过,计划在 9:00 AM 发出警报,但 onReceive 仅在 9:46 AM 执行,这意味着我解锁设备的那一刻。 这是我的新代码:
Intent intent = new Intent("com.blah.something.ALARM_RECEIVED");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delayInMs, pendingIntent);
就是说,出于某种原因,我写的日志 "start of onReceive" 并不是真的在侦听器的开头。刚好放在real的开头,看看有没有调用listener。
编辑 2016 年 12 月 5 日: 因此,我更改了 onReceive 顶部的日志写入,并发生了同样的问题:一旦我手动唤醒设备,就会调用 onReceive 的开始。 我可以实现 wakefulBroadcastReceiver,但我担心它不会解决任何问题。如果我理解正确,wakefulBroadcastReceiver 可用于防止设备在 onReceive 和 activity 或服务启动之间休眠。但是,如果甚至没有调用 onReceive 怎么办? 我有点绝望……也许我应该直接问索尼。 此外,我的 phone 有耐力模式,但没有激活。
编辑 2016 年 12 月 11 日: 因此,通过更多测试,我现在确定我什么都不懂……我设置了一个每 5 分钟激活一次的 broadcastReceiver(onReceive 在 5 分钟后重置 alarmManager),我可以看到它工作正常……有时.它可以持续几个小时,然后睡两个小时,然后 30 分钟就可以了,然后再睡。 (当我的 phone 打开、拔下电源并闲置时,所有这些)。 我将删除所有我们感兴趣的代码。它会更容易理解,我将能够在这里编写所有活动代码。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.par.hasard.mysimpleapplication">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.par.hasard.mysimpleapplication.MySimpleReceiver">
<intent-filter android:priority="1">
<action android:name="com.par.hasard.mysimpleapplication.REGULAR_ALARM" />
</intent-filter>
</receiver>
</application>
</manifest>
MainActivity.java
package com.par.hasard.mysimpleapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.myExportButton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MyLogManager.copyLogToClipboard(view.getContext());
MyLogManager.emptyLogFile(view.getContext());
}
});
try {
MyLogManager.createLogFile(this);
MyLogManager.write(this, "Application launched\n");
MyAlarmPlanner.planAlarm(this);
} catch (Exception e) {
e.printStackTrace();
}
}
}
MySimpleReceiver.java
package com.par.hasard.mysimpleapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MySimpleReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
MyLogManager.write(context, "Beginning of onReceive\n");
MyAlarmPlanner.planAlarm(context);
MyLogManager.write(context, "End of onReceive\n");
} catch (Exception e) {
e.printStackTrace();
}
}
}
MyAlarmPlanner.java
package com.par.hasard.mysimpleapplication;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import java.io.IOException;
public class MyAlarmPlanner {
public static void planAlarm(Context context) throws IOException {
MyLogManager.write(context, "Beginning of alarm planning\n");
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent("com.par.hasard.mysimpleapplication.REGULAR_ALARM");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.cancel(pendingIntent);
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 300000, pendingIntent);
MyLogManager.write(context, "End of alarm planning\n");
}
}
我觉得MyLogManager.java没什么用,就是无聊的文件管理方法。
长时间空闲后的日志文件内容:
12/12 15h33m23s380 => Beginning of onReceive
12/12 15h33m23s381 => Beginning of alarm planning
12/12 15h33m23s383 => End of alarm planning
12/12 15h33m23s384 => End of onReceive
12/12 15h38m24s337 => Beginning of onReceive
12/12 15h38m24s339 => Beginning of alarm planning
12/12 15h38m24s375 => End of alarm planning
12/12 15h38m24s376 => End of onReceive
12/12 15h43m24s375 => Beginning of onReceive
12/12 15h43m24s376 => Beginning of alarm planning
12/12 15h43m24s380 => End of alarm planning
12/12 15h43m24s381 => End of onReceive
12/12 15h48m25s301 => Beginning of onReceive
12/12 15h48m25s304 => Beginning of alarm planning
12/12 15h48m25s307 => End of alarm planning
12/12 15h48m25s308 => End of onReceive
12/12 15h53m25s316 => Beginning of onReceive
12/12 15h53m25s318 => Beginning of alarm planning
12/12 15h53m25s328 => End of alarm planning
12/12 15h53m25s329 => End of onReceive
12/12 15h58m25s328 => Beginning of onReceive
12/12 15h58m25s329 => Beginning of alarm planning
12/12 15h58m25s331 => End of alarm planning
12/12 15h58m25s333 => End of onReceive
12/12 16h3m26s336 => Beginning of onReceive
12/12 16h3m26s351 => Beginning of alarm planning
12/12 16h3m26s379 => End of alarm planning
12/12 16h3m26s380 => End of onReceive
12/12 16h8m26s397 => Beginning of onReceive
12/12 16h8m26s401 => Beginning of alarm planning
12/12 16h8m26s404 => End of alarm planning
12/12 16h8m26s405 => End of onReceive
12/12 16h13m26s406 => Beginning of onReceive
12/12 16h13m26s407 => Beginning of alarm planning
12/12 16h13m26s410 => End of alarm planning
12/12 16h13m26s411 => End of onReceive
12/12 16h18m27s328 => Beginning of onReceive
12/12 16h18m27s329 => Beginning of alarm planning
12/12 16h18m27s346 => End of alarm planning
12/12 16h18m27s348 => End of onReceive
12/12 16h23m28s298 => Beginning of onReceive
12/12 16h23m28s299 => Beginning of alarm planning
12/12 16h23m28s303 => End of alarm planning
12/12 16h23m28s304 => End of onReceive
12/12 16h28m29s308 => Beginning of onReceive
12/12 16h28m29s310 => Beginning of alarm planning
12/12 16h28m29s323 => End of alarm planning
12/12 16h28m29s324 => End of onReceive
12/12 16h33m29s339 => Beginning of onReceive
12/12 16h33m29s340 => Beginning of alarm planning
12/12 16h33m29s355 => End of alarm planning
12/12 16h33m29s361 => End of onReceive
12/12 16h38m29s356 => Beginning of onReceive
12/12 16h38m29s357 => Beginning of alarm planning
12/12 16h38m29s360 => End of alarm planning
12/12 16h38m29s361 => End of onReceive
12/12 16h43m29s364 => Beginning of onReceive
12/12 16h43m29s365 => Beginning of alarm planning
12/12 16h43m29s367 => End of alarm planning
12/12 16h43m29s369 => End of onReceive
12/12 16h48m29s376 => Beginning of onReceive
12/12 16h48m29s380 => Beginning of alarm planning
12/12 16h48m29s390 => End of alarm planning
12/12 16h48m29s394 => End of onReceive
12/12 16h53m29s392 => Beginning of onReceive
12/12 16h53m29s394 => Beginning of alarm planning
12/12 16h53m29s402 => End of alarm planning
12/12 16h53m29s403 => End of onReceive
12/12 17h43m33s986 => Beginning of onReceive //problem, the 16'58 onReceive wasn't called
12/12 17h43m33s988 => Beginning of alarm planning
12/12 17h43m33s996 => End of alarm planning
12/12 17h43m34s4 => End of onReceive
12/12 17h48m34s535 => Beginning of onReceive
12/12 17h48m34s536 => Beginning of alarm planning
12/12 17h48m34s539 => End of alarm planning
12/12 17h48m34s540 => End of onReceive
12/12 18h29m49s635 => Beginning of onReceive //the moment I turned on my device
12/12 18h29m49s648 => Beginning of alarm planning
12/12 18h29m49s667 => End of alarm planning
12/12 18h29m49s668 => End of onReceive
谁能告诉我我的错误在哪里?
执行此操作的正确方法是让您的 AlarmManager 触发 BroadcastReceiver 而不是直接 Activity。然后,您可以将唤醒锁放在广播接收器 class 内,然后 运行 您的 activity 来自 BroadcastReceiver 或来自从 BroadcastReceiver 启动的 IntentService。
您的意图将更改为:
Intent intent = new Intent(context, MyActivityReceiver.class);
然后制作你的广播接收器:
package com.yourpackage (change this to your package)
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyActivityReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 0; //only necessary if you have more receivers
// when the alarm is triggered
@Override
public void onReceive(Context context, Intent intent) {
wakeLock = ((PowerManager)contexte.getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, "MyActivity");
wakeLock.acquire();
Intent i = new Intent(context, MyActivity.class);
context.startService(i);
}
}
并将收件人添加到您的清单中:
<receiver
android:name="service.TimeService"
android:enabled="true"
android:exported="false"
>
</receiver>
如果这不起作用,那么您需要通过 WakefulService 启动 activity。
android 中的 AlarmManager api 有其局限性。对于 -
- 它在设备重启时被清除(所有警报丢失)
- 在设备 lock/sleep 状态 lock/sleep 期间,其行为在制造商和 android 版本之间不一致
我解决这些问题的方法是 -
- 创建具有广播意图的警报,然后将侦听器添加到该广播以执行必要的操作。
像这样-
Intent intent = new Intent("com.blah.something.ALARM_RECIEVED");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Html5Activity.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, triggerTimeInMillis, pendingIntent);
清单文件 -
<receiver android:name=".receiver.BackgroundScheduledAlarmReceiver">
<intent-filter android:priority="1">
<action android:name="com.blah.something.ALARM_RECIEVED" />
</intent-filter>
</receiver>
- 将警报保存在 sqlite 或其他地方(此处未显示)并在设备重启时通过像这样侦听设备启动来重新创建它们 -
清单文件 -
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<receiver
android:name=".receiver.RecreateAlarmsAtBootReceiver"
android:enabled="true"
android:exported="true"
android:label="RecreateAlarmsAtBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
在RecreateAlarmsAtBootReceiver
中,读取存储报警的sqlite,重新添加到报警管理器中。
感谢CommonsWare,问题解决了!此失败是由于打瞌睡模式 (https://developer.android.com/training/monitoring-device-state/doze-standby.html)
简而言之,自 Android 6.0 起,AlarmManager 会受到影响,并且如果设备处于此休眠模式则无法触发。但是您可以将 setExact 替换为 setExactAndAllowWhileIdle。有局限性,但我们必须应对。 CommonsWare 回答了 link 到 post 的问题: