用于长期通知的 AlarmManager - 它有效
AlarmManager for long term notifications - it works
跳到下面我的回答
我看过类似的问题,但没有合适或正确的答案,有些甚至是矛盾的。
问题很简单:alarmManager不能长时间工作(几个小时以上)吗?
我有一个包含消息数组的应用程序。一开始运行,每条消息都有一个个人时间(Calendar obj),应用程序为每个消息设置一个alarmManager,并将所有消息保存在sharedPreference。下面的代码(我当然只复制了相关的代码)工作正常,即使我重启设备(感谢 sharedPref)几个小时然后停止发送通知。
如果我将整个消息发送时间设置为短期(假设:10 条消息,每 5 分钟 1 条消息)效果很好,它们都已发送。但是如果我每小时安排一次,它只在前 2-3 小时有效。
我看到一些答案说 alarmManager 不适合长期使用,而其他答案说它是完美的服务:(有人能给我一个专业的答案吗?
我也尝试了alarmManager.setAlarmClock()和setExactAndAllowWhileIdle()但结果相同。
好的,经过长时间的挖掘,我想我明白了。现在可以用了,重启后,通知又回来了。
我 post 我的代码在这里,首先是给任何寻找解决方案的人,其次 - 我想听听你的意见 - 如果我做对了等等。Tnx
msg.activity
private void addAlerts (MyMsg myMsg) {
MyReceiver rc = new MyReceiver ();
for (int i = 1; i < myMsg.totalMsgNum; i++)
rc.setSingleNotifications (this, myMsg.msg[i]);
}
MyReciever.java
public class MyReceiver extends BroadcastReceiver {
final String CHANNEL_ID = "777";
SharedPreferences pref;
SharedPreferences.Editor editor;
@Override
public void onReceive (Context context, Intent intent) {
// get the relevant content
pref = context.getSharedPreferences ("SAVED_FILE", Context.MODE_PRIVATE);
int atMsgNum = pref.getInt ("CURRENT", 1);
String json = pref.getString ("USER_OBJ", "");
Gson gson = new Gson ();
User user = gson.fromJson (json, User.class);
String titleStr = user.msg[atMsgNum].title;
String contentStr = user.msg[atMsgNum].msg;
// update current msg num
editor = pref.edit ();
editor.putInt ("CURRENT", atMsgNum + 1);
editor.commit ();
// intent for showing the msg activity
intent.setClass (context, OnPressNotificationActivity.class);
intent.putExtra ("ID", atMsgNum);
intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// notification
createNotificationChannel (context);
TaskStackBuilder stackBuilder = TaskStackBuilder.create (context);
stackBuilder.addNextIntentWithParentStack (intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent (atMsgNum, 0);
NotificationCompat.Builder builder;
builder = new NotificationCompat.Builder (context, CHANNEL_ID)
.setSmallIcon (R.drawable.single_pics_logo)
.setContentTitle (titleStr)
.setContentText (contentStr)
.setStyle (new NotificationCompat.BigTextStyle ()
.bigText (contentStr))
.setPriority (NotificationCompat.PRIORITY_HIGH)
.setContentIntent (pendingIntent)
.setAutoCancel (true)
.setBadgeIconType (NotificationCompat.BADGE_ICON_SMALL)
.setVisibility (NotificationCompat.VISIBILITY_PUBLIC);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from (context);
notificationManager.notify (atMsgNum, builder.build ());
}
public void setSingleNotifications (Context context, Msg msg) {
Intent intent = new Intent (context, MyReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast (context, msg.num, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance ();
calendar.setTimeInMillis (System.currentTimeMillis ());
calendar.set (Calendar.YEAR, msg.calendar.get (Calendar.YEAR));
calendar.set (Calendar.MONTH, msg.calendar.get (Calendar.MONTH));
calendar.set (Calendar.DAY_OF_MONTH, msg.calendar.get (Calendar.DAY_OF_MONTH));
calendar.set (Calendar.HOUR_OF_DAY, msg.calendar.get (Calendar.HOUR_OF_DAY));
calendar.set (Calendar.MINUTE, msg.calendar.get (Calendar.MINUTE));
calendar.set (Calendar.SECOND, msg.calendar.get (Calendar.SECOND));
calendar.add (Calendar.SECOND, 2);
AlarmManager alarmManager = (AlarmManager) context.getSystemService (ALARM_SERVICE);
AlarmManager.AlarmClockInfo almInfo = new AlarmManager.AlarmClockInfo (calendar.getTimeInMillis (), null);
alarmManager.setAlarmClock (almInfo, alarmIntent);
}
private void createNotificationChannel (Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
CharSequence name = "myMsgApp";
String description = "daily alert";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel (CHANNEL_ID, name, importance);
channel.setDescription (description);
NotificationManager notificationManager = context.getSystemService (NotificationManager.class);
notificationManager.createNotificationChannel (channel);
}
}
}
RestartReceiver.java // 重启
public class RestartReceiver extends BroadcastReceiver {
@Override
public void onReceive (Context context, Intent intent) { // restarts alarms only when device restart
if (intent.getAction ().equals ("android.intent.action.BOOT_COMPLETED")) {
SharedPreferences sharedPreferences = context.getSharedPreferences ("SAVED_FILE", context.MODE_PRIVATE);
String json = sharedPreferences.getString ("USER_OBJ", "");
Intent in = new Intent (context, RestartService.class);
in.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); // ??
in.putExtra ("JSON_STRING", json);
in.putExtra ("CURRENT", sharedPreferences.getInt ("CURRENT", 1));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
context.startForegroundService (in);
else
context.startService (in);
}
}
}
RestartService.java
public class RestartService extends IntentService {
public RestartService () {
super ("RestartService");
}
public RestartService (String name) {
super (name);
}
@Override
protected void onHandleIntent (@Nullable Intent intent) {
String json = intent.getExtras ().getString ("JSON_STRING", "");
Gson gson = new Gson ();
User user = gson.fromJson (json, User.class);
user.atMsgNum = intent.getExtras ().getInt ("CURRENT", 1);
MyReceiver rc = new MyReceiver ();
for (int i = user.atMsgNum; i < user.totalMsgNum; i++)
rc.setSingleNotifications (this, user.msg [i]);
}
}
AndroidManifest 包括:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
<action android:name="android.media.action.DISPLAY_NOTIFICATION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver
android:name=".RestartReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="myPackageName.RestartService"
android:exported="false"/>
跳到下面我的回答
我看过类似的问题,但没有合适或正确的答案,有些甚至是矛盾的。
问题很简单:alarmManager不能长时间工作(几个小时以上)吗?
我有一个包含消息数组的应用程序。一开始运行,每条消息都有一个个人时间(Calendar obj),应用程序为每个消息设置一个alarmManager,并将所有消息保存在sharedPreference。下面的代码(我当然只复制了相关的代码)工作正常,即使我重启设备(感谢 sharedPref)几个小时然后停止发送通知。
如果我将整个消息发送时间设置为短期(假设:10 条消息,每 5 分钟 1 条消息)效果很好,它们都已发送。但是如果我每小时安排一次,它只在前 2-3 小时有效。
我看到一些答案说 alarmManager 不适合长期使用,而其他答案说它是完美的服务:(有人能给我一个专业的答案吗?
我也尝试了alarmManager.setAlarmClock()和setExactAndAllowWhileIdle()但结果相同。
好的,经过长时间的挖掘,我想我明白了。现在可以用了,重启后,通知又回来了。
我 post 我的代码在这里,首先是给任何寻找解决方案的人,其次 - 我想听听你的意见 - 如果我做对了等等。Tnx
msg.activity
private void addAlerts (MyMsg myMsg) {
MyReceiver rc = new MyReceiver ();
for (int i = 1; i < myMsg.totalMsgNum; i++)
rc.setSingleNotifications (this, myMsg.msg[i]);
}
MyReciever.java
public class MyReceiver extends BroadcastReceiver {
final String CHANNEL_ID = "777";
SharedPreferences pref;
SharedPreferences.Editor editor;
@Override
public void onReceive (Context context, Intent intent) {
// get the relevant content
pref = context.getSharedPreferences ("SAVED_FILE", Context.MODE_PRIVATE);
int atMsgNum = pref.getInt ("CURRENT", 1);
String json = pref.getString ("USER_OBJ", "");
Gson gson = new Gson ();
User user = gson.fromJson (json, User.class);
String titleStr = user.msg[atMsgNum].title;
String contentStr = user.msg[atMsgNum].msg;
// update current msg num
editor = pref.edit ();
editor.putInt ("CURRENT", atMsgNum + 1);
editor.commit ();
// intent for showing the msg activity
intent.setClass (context, OnPressNotificationActivity.class);
intent.putExtra ("ID", atMsgNum);
intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
// notification
createNotificationChannel (context);
TaskStackBuilder stackBuilder = TaskStackBuilder.create (context);
stackBuilder.addNextIntentWithParentStack (intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent (atMsgNum, 0);
NotificationCompat.Builder builder;
builder = new NotificationCompat.Builder (context, CHANNEL_ID)
.setSmallIcon (R.drawable.single_pics_logo)
.setContentTitle (titleStr)
.setContentText (contentStr)
.setStyle (new NotificationCompat.BigTextStyle ()
.bigText (contentStr))
.setPriority (NotificationCompat.PRIORITY_HIGH)
.setContentIntent (pendingIntent)
.setAutoCancel (true)
.setBadgeIconType (NotificationCompat.BADGE_ICON_SMALL)
.setVisibility (NotificationCompat.VISIBILITY_PUBLIC);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from (context);
notificationManager.notify (atMsgNum, builder.build ());
}
public void setSingleNotifications (Context context, Msg msg) {
Intent intent = new Intent (context, MyReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast (context, msg.num, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance ();
calendar.setTimeInMillis (System.currentTimeMillis ());
calendar.set (Calendar.YEAR, msg.calendar.get (Calendar.YEAR));
calendar.set (Calendar.MONTH, msg.calendar.get (Calendar.MONTH));
calendar.set (Calendar.DAY_OF_MONTH, msg.calendar.get (Calendar.DAY_OF_MONTH));
calendar.set (Calendar.HOUR_OF_DAY, msg.calendar.get (Calendar.HOUR_OF_DAY));
calendar.set (Calendar.MINUTE, msg.calendar.get (Calendar.MINUTE));
calendar.set (Calendar.SECOND, msg.calendar.get (Calendar.SECOND));
calendar.add (Calendar.SECOND, 2);
AlarmManager alarmManager = (AlarmManager) context.getSystemService (ALARM_SERVICE);
AlarmManager.AlarmClockInfo almInfo = new AlarmManager.AlarmClockInfo (calendar.getTimeInMillis (), null);
alarmManager.setAlarmClock (almInfo, alarmIntent);
}
private void createNotificationChannel (Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
CharSequence name = "myMsgApp";
String description = "daily alert";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel (CHANNEL_ID, name, importance);
channel.setDescription (description);
NotificationManager notificationManager = context.getSystemService (NotificationManager.class);
notificationManager.createNotificationChannel (channel);
}
}
}
RestartReceiver.java // 重启
public class RestartReceiver extends BroadcastReceiver {
@Override
public void onReceive (Context context, Intent intent) { // restarts alarms only when device restart
if (intent.getAction ().equals ("android.intent.action.BOOT_COMPLETED")) {
SharedPreferences sharedPreferences = context.getSharedPreferences ("SAVED_FILE", context.MODE_PRIVATE);
String json = sharedPreferences.getString ("USER_OBJ", "");
Intent in = new Intent (context, RestartService.class);
in.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); // ??
in.putExtra ("JSON_STRING", json);
in.putExtra ("CURRENT", sharedPreferences.getInt ("CURRENT", 1));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
context.startForegroundService (in);
else
context.startService (in);
}
}
}
RestartService.java
public class RestartService extends IntentService {
public RestartService () {
super ("RestartService");
}
public RestartService (String name) {
super (name);
}
@Override
protected void onHandleIntent (@Nullable Intent intent) {
String json = intent.getExtras ().getString ("JSON_STRING", "");
Gson gson = new Gson ();
User user = gson.fromJson (json, User.class);
user.atMsgNum = intent.getExtras ().getInt ("CURRENT", 1);
MyReceiver rc = new MyReceiver ();
for (int i = user.atMsgNum; i < user.totalMsgNum; i++)
rc.setSingleNotifications (this, user.msg [i]);
}
}
AndroidManifest 包括:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
<action android:name="android.media.action.DISPLAY_NOTIFICATION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver
android:name=".RestartReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="myPackageName.RestartService"
android:exported="false"/>