Android: phone 重启后设置 alarm/reminder
Android: set alarm/reminder after phone reboot
我正在开发一个集成了提醒功能的 Android 应用程序。
如果 phone 保持打开状态,通知会起作用,但是当我将其关闭或重新启动时,我会丢失所有警报。
我知道这是 Android 功能,可以提高 phone 效率,但我不知道该怎么办,我该如何解决这个问题?
这是我的文件:
AlarmService.java
AlarmReceiver.java
开机AlarmReceiver.java
AndroidManifest.xml
"AlarmService.java"在phone打开时被"BootAlarmReceiver.java"调用,它应该,但它没有,重新加载所有我的闹钟。
"AlarmReceiver.java" 在 AlarmManager 发出警报时调用。
这里是代码:
AlarmService.java
public class AlarmService extends IntentService {
public AlarmService() {
super("AlarmService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Calendar calendar = Calendar.getInstance();
FileInputStream fileInputStream = null;
int requestCode, year, month, day, hour, minute;
String note, with;
try {
fileInputStream = openFileInput("my_alarms.csv");
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String row;
while ((row = bufferedReader.readLine()) != null) {
String[] splittedRow = row.split(";");
requestCode = Integer.valueOf(splittedRow[0]);
year = Integer.valueOf(splittedRow[1]);
month = Integer.valueOf(splittedRow[2]);
day = Integer.valueOf(splittedRow[3]);
hour = Integer.valueOf(splittedRow[4]);
minute = Integer.valueOf(splittedRow[5]);
note = splittedRow[6];
with = splittedRow[7];
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
alarmIntent.putExtra("note", note + "\nCon: " + with);
alarmIntent.putExtra("title", "My Memo");
alarmIntent.putExtra("alarm", "memo");
//requestCode must be incremental to create multiple reminders
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, requestCode, alarmIntent, 0);
if (calendar.before(Calendar.getInstance())) {
calendar.add(Calendar.DATE, 1);
}
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getStringExtra("alarm").equals("memo")) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@SuppressLint("WrongConstant") NotificationChannel notificationChannel = new NotificationChannel("memo_channel", "My Memo", NotificationManager.IMPORTANCE_MAX);
notificationChannel.setDescription("Memo Notification Channel");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.BLUE);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, "memo_channel");
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setTicker("Reminder")
.setContentTitle("Memo")
.setContentText(intent.getStringExtra("note"))
.setContentInfo("Information")
.setSmallIcon(R.drawable.ic_alarm);
notificationManager.notify(1, notificationBuilder.build());
}
}
}
开机AlarmReceiver.java
public class BootAlarmReceiver extends BroadcastReceiver {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
Intent alarmServiceIntent = new Intent(context, AlarmService.class);
ComponentName service = context.startService(alarmServiceIntent);
if (service == null) {
Log.e("ALARM", "Could not start service");
} else {
Log.e("ALARM", "Could start service");
}
}
}
}
AndroidManifest.xml
<manifest>
<application>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
//Other code here
<receiver
android:name=".BootAlarmReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReceiver" />
<service android:name=".AlarmService" />
</application>
</manifest>
请帮助我,谢谢你的时间。
编辑
我在打开设备时发现这个错误:
java.lang.RuntimeException: Unable to start receiver com.package.appname.BootAlarmReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { act=REBOOT cmp=com.package.appname/.AlarmService }: app is in background uid UidRecord{a5a4cb2 u0a341 RCVR idle change:uncached procs:1 seq(0,0,0)}
我该怎么办?
一些品牌正在使用额外的政策来加快启动和电池优化。例如小米对此有自动启动权限。如果您希望您的警报在重启后不间断地继续,您必须被授予此权限。 (Settings/Apps/Your app/Auto 开始)。很多厂商都有这样的东西。
你能做什么?
您可以通过编程方式请求自动启动权限,或者请求忽略电池优化权限。
这些 question/answers 会对您有所帮助
编辑:您的日志显示您无权在启动完成后启动您的服务。
您必须 google "how to whitelist your app in LG6" 和 "how to get auto start permission for LG"。因为这个问题与品牌和设备有关。我不可能确切地告诉你应该做什么。
即使你说你检查了一切,也缺少权限
解决方案:
大家好,我发现了我遇到的问题,我的代码是正确的并且工作正常,问题出在我设备的 OS 中,来自 Android OS Oreo 启动服务的命令已更改,需要新的命令语法:
变化在"BootAlarmReceiver.java"
前一个代码:
public class BootAlarmReceiver extends BroadcastReceiver {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
Intent alarmServiceIntent = new Intent(context, AlarmService.class);
ComponentName service = context.startService(alarmServiceIntent);
if (service == null) {
Log.e("ALARM", "Could not start service");
} else {
Log.e("ALARM", "Could start service");
}
}
}
}
新代码:
public class BootAlarmReceiver extends BroadcastReceiver {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
Intent alarmServiceIntent = new Intent(context, AlarmService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(alarmServiceIntent);
} else {
context.startService(alarmServiceIntent);
}
}
}
}
所以如果你是 运行 奥利奥或更新你应该使用 .startForegroundService(yourIntent)
,否则你应该使用 .startService(yourIntent)
.
此解决方案也适用于您。
我正在开发一个集成了提醒功能的 Android 应用程序。 如果 phone 保持打开状态,通知会起作用,但是当我将其关闭或重新启动时,我会丢失所有警报。 我知道这是 Android 功能,可以提高 phone 效率,但我不知道该怎么办,我该如何解决这个问题?
这是我的文件:
AlarmService.java
AlarmReceiver.java
开机AlarmReceiver.java
AndroidManifest.xml
"AlarmService.java"在phone打开时被"BootAlarmReceiver.java"调用,它应该,但它没有,重新加载所有我的闹钟。 "AlarmReceiver.java" 在 AlarmManager 发出警报时调用。
这里是代码:
AlarmService.java
public class AlarmService extends IntentService {
public AlarmService() {
super("AlarmService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Calendar calendar = Calendar.getInstance();
FileInputStream fileInputStream = null;
int requestCode, year, month, day, hour, minute;
String note, with;
try {
fileInputStream = openFileInput("my_alarms.csv");
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String row;
while ((row = bufferedReader.readLine()) != null) {
String[] splittedRow = row.split(";");
requestCode = Integer.valueOf(splittedRow[0]);
year = Integer.valueOf(splittedRow[1]);
month = Integer.valueOf(splittedRow[2]);
day = Integer.valueOf(splittedRow[3]);
hour = Integer.valueOf(splittedRow[4]);
minute = Integer.valueOf(splittedRow[5]);
note = splittedRow[6];
with = splittedRow[7];
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
alarmIntent.putExtra("note", note + "\nCon: " + with);
alarmIntent.putExtra("title", "My Memo");
alarmIntent.putExtra("alarm", "memo");
//requestCode must be incremental to create multiple reminders
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, requestCode, alarmIntent, 0);
if (calendar.before(Calendar.getInstance())) {
calendar.add(Calendar.DATE, 1);
}
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getStringExtra("alarm").equals("memo")) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@SuppressLint("WrongConstant") NotificationChannel notificationChannel = new NotificationChannel("memo_channel", "My Memo", NotificationManager.IMPORTANCE_MAX);
notificationChannel.setDescription("Memo Notification Channel");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.BLUE);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, "memo_channel");
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setTicker("Reminder")
.setContentTitle("Memo")
.setContentText(intent.getStringExtra("note"))
.setContentInfo("Information")
.setSmallIcon(R.drawable.ic_alarm);
notificationManager.notify(1, notificationBuilder.build());
}
}
}
开机AlarmReceiver.java
public class BootAlarmReceiver extends BroadcastReceiver {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
Intent alarmServiceIntent = new Intent(context, AlarmService.class);
ComponentName service = context.startService(alarmServiceIntent);
if (service == null) {
Log.e("ALARM", "Could not start service");
} else {
Log.e("ALARM", "Could start service");
}
}
}
}
AndroidManifest.xml
<manifest>
<application>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
//Other code here
<receiver
android:name=".BootAlarmReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReceiver" />
<service android:name=".AlarmService" />
</application>
</manifest>
请帮助我,谢谢你的时间。
编辑
我在打开设备时发现这个错误:
java.lang.RuntimeException: Unable to start receiver com.package.appname.BootAlarmReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { act=REBOOT cmp=com.package.appname/.AlarmService }: app is in background uid UidRecord{a5a4cb2 u0a341 RCVR idle change:uncached procs:1 seq(0,0,0)}
我该怎么办?
一些品牌正在使用额外的政策来加快启动和电池优化。例如小米对此有自动启动权限。如果您希望您的警报在重启后不间断地继续,您必须被授予此权限。 (Settings/Apps/Your app/Auto 开始)。很多厂商都有这样的东西。
你能做什么?
您可以通过编程方式请求自动启动权限,或者请求忽略电池优化权限。
这些 question/answers 会对您有所帮助
编辑:您的日志显示您无权在启动完成后启动您的服务。
您必须 google "how to whitelist your app in LG6" 和 "how to get auto start permission for LG"。因为这个问题与品牌和设备有关。我不可能确切地告诉你应该做什么。
即使你说你检查了一切,也缺少权限
解决方案:
大家好,我发现了我遇到的问题,我的代码是正确的并且工作正常,问题出在我设备的 OS 中,来自 Android OS Oreo 启动服务的命令已更改,需要新的命令语法:
变化在"BootAlarmReceiver.java"
前一个代码:
public class BootAlarmReceiver extends BroadcastReceiver {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
Intent alarmServiceIntent = new Intent(context, AlarmService.class);
ComponentName service = context.startService(alarmServiceIntent);
if (service == null) {
Log.e("ALARM", "Could not start service");
} else {
Log.e("ALARM", "Could start service");
}
}
}
}
新代码:
public class BootAlarmReceiver extends BroadcastReceiver {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
Intent alarmServiceIntent = new Intent(context, AlarmService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(alarmServiceIntent);
} else {
context.startService(alarmServiceIntent);
}
}
}
}
所以如果你是 运行 奥利奥或更新你应该使用 .startForegroundService(yourIntent)
,否则你应该使用 .startService(yourIntent)
.
此解决方案也适用于您。