Android 8.0 - BroadcastReceiver 重启后收不到
Android 8.0 - BroadcastReceiver not receiving after a reboot
我正在开发一个应用程序。我面临一个问题。问题是我的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.a5corp.weather">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher_x"
android:label="@string/app_name"
android:fullBackupContent="@xml/backup_rules"
android:theme="@style/AppTheme.NoActionBar">
...
<service android:name=".service.NotificationService" />
<receiver
android:name=".receiver.StartupReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.UpgradeReceiver">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
...
</application>
</manifest>
启动接收器:
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
...
NotificationService.setNotificationServiceAlarm(context, new Prefs(context).getNotifs());
}
else
Log.i("No" , "Boot");
}
}
升级接收器:
public class UpgradeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("In" , UpgradeReceiver.class.getSimpleName());
NotificationService.setNotificationServiceAlarm(context , new Prefs(context).getNotifs());
}
}
通知服务:
public class NotificationService extends IntentService {
private static final String TAG = "NotificationsService";
Prefs prefs;
Notification.Builder builder;
public NotificationService() {
super(TAG);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
@Override
protected void onHandleIntent(Intent intent) {
CheckConnection checkNetwork = new CheckConnection(this);
if (!checkNetwork.isNetworkAvailable()) {
return;
}
...
try {
WeatherInfo weather;
weather = new Request(this).getItems(city, units);
weatherNotification(weather);
} catch (IOException e) {
Log.e(TAG, "Error get weather", e);
}
}
public static Intent newIntent(Context context) {
Log.i("Trigger" , "newIntent");
return new Intent(context, NotificationService.class);
}
public static void setNotificationServiceAlarm(Context context,
boolean isNotificationEnable) {
Log.i("In" , "Notification Service Alarm");
Intent intent = NotificationService.newIntent(context);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
long intervalMillis = AlarmManager.INTERVAL_HOUR;
if (alarmManager != null)
if (isNotificationEnable) {
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
intervalMillis,
pendingIntent);
} else {
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
}
}
private void weatherNotification(WeatherInfo weather) {
Intent intent = new Intent(this, WeatherActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
...
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert notificationManager != null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String id = "w01", name = getString(R.string.weather_notification_title);
int importance = NotificationManager.IMPORTANCE_MIN;
String desc = getString(R.string.weather_notification_description);
NotificationChannel channel = new NotificationChannel(id, name, importance);
channel.setDescription(desc);
notificationManager.createNotificationChannel(channel);
builder = new Notification.Builder(this , id);
}
else
builder = new Notification.Builder(this);
...
Notification notification = builder.build();
notificationManager.notify(0 , notification);
}
}
问题在于 NotificationService 本身可以独立运行,但是当应用程序升级或 phone 重新启动时不会调用它。事实上,这发生在 Android O 上。据我所知,在我升级到 Android 8.
之前,这曾经在 Android 7.1 上工作
编辑 1: 在尝试了 JobIntentService 之后,我的代码现在是这样的:
更新清单:
...
<service android:name=".service.ReactivationService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
...
重新激活服务:
public class ReactivationService extends JobIntentService {
public static final int JOB_ID = 0x01;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, ReactivationService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
Log.i("In" , "onHandleWork()");
....
NotificationService.setNotificationServiceAlarm(this, new Prefs(this).getNotifs());
}
}
启动接收器:
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.i("In" , "getAction()");
ReactivationService.enqueueWork(context, intent);
}
else
Log.i("No" , "Boot");
}
}
升级接收器:
public class UpgradeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_MY_PACKAGE_REPLACED)) {
Log.i("In" , "getAction()");
ReactivationService.enqueueWork(context, intent);
}
else
Log.i("No" , "Upgrade");
}
}
现在我的问题是,ACTION_MY_PACKAGE_REPLACED 工作正常并显示了通知,但 ACTION_BOOT_COMPLETED 没有显示通知。可能是什么原因,因为我为两个接收者使用相同的服务。
从Android开始 O,你不能从后台应用程序启动服务而不会出现异常:
java.lang.IllegalStateException: Not allowed to start service Intent
(my_service) : app is in background
如果您仍然需要在设备启动时启动服务,您现在可以使用新的 JobIntentService。
将您的 IntentService
更改为 JobIntentService
:
public class ReactivationService extends JobIntentService {
public static final int JOB_ID = 0x01;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, ReactivationService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
// do your stuff here
}
}
在您的 StartupReceiver
中按如下方式使用它:
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
ReactivationService.enqueueWork(context, new Intent());
}
}
}
在清单中声明您的服务:
<service android:name=".ReactivationService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
就是这样。这将直接启动服务(在 O 之前的平台上 运行 时)或将其作为作业排队(在 O 及更高版本上 运行 时)。不管是什么平台,你在enqueueWork
中传递的一切,最终都会出现在onHandleWork
.
中
我正在开发一个应用程序。我面临一个问题。问题是我的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.a5corp.weather">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher_x"
android:label="@string/app_name"
android:fullBackupContent="@xml/backup_rules"
android:theme="@style/AppTheme.NoActionBar">
...
<service android:name=".service.NotificationService" />
<receiver
android:name=".receiver.StartupReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.UpgradeReceiver">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
...
</application>
</manifest>
启动接收器:
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
...
NotificationService.setNotificationServiceAlarm(context, new Prefs(context).getNotifs());
}
else
Log.i("No" , "Boot");
}
}
升级接收器:
public class UpgradeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("In" , UpgradeReceiver.class.getSimpleName());
NotificationService.setNotificationServiceAlarm(context , new Prefs(context).getNotifs());
}
}
通知服务:
public class NotificationService extends IntentService {
private static final String TAG = "NotificationsService";
Prefs prefs;
Notification.Builder builder;
public NotificationService() {
super(TAG);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
@Override
protected void onHandleIntent(Intent intent) {
CheckConnection checkNetwork = new CheckConnection(this);
if (!checkNetwork.isNetworkAvailable()) {
return;
}
...
try {
WeatherInfo weather;
weather = new Request(this).getItems(city, units);
weatherNotification(weather);
} catch (IOException e) {
Log.e(TAG, "Error get weather", e);
}
}
public static Intent newIntent(Context context) {
Log.i("Trigger" , "newIntent");
return new Intent(context, NotificationService.class);
}
public static void setNotificationServiceAlarm(Context context,
boolean isNotificationEnable) {
Log.i("In" , "Notification Service Alarm");
Intent intent = NotificationService.newIntent(context);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
long intervalMillis = AlarmManager.INTERVAL_HOUR;
if (alarmManager != null)
if (isNotificationEnable) {
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
intervalMillis,
pendingIntent);
} else {
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
}
}
private void weatherNotification(WeatherInfo weather) {
Intent intent = new Intent(this, WeatherActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
...
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert notificationManager != null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String id = "w01", name = getString(R.string.weather_notification_title);
int importance = NotificationManager.IMPORTANCE_MIN;
String desc = getString(R.string.weather_notification_description);
NotificationChannel channel = new NotificationChannel(id, name, importance);
channel.setDescription(desc);
notificationManager.createNotificationChannel(channel);
builder = new Notification.Builder(this , id);
}
else
builder = new Notification.Builder(this);
...
Notification notification = builder.build();
notificationManager.notify(0 , notification);
}
}
问题在于 NotificationService 本身可以独立运行,但是当应用程序升级或 phone 重新启动时不会调用它。事实上,这发生在 Android O 上。据我所知,在我升级到 Android 8.
之前,这曾经在 Android 7.1 上工作编辑 1: 在尝试了 JobIntentService 之后,我的代码现在是这样的:
更新清单:
...
<service android:name=".service.ReactivationService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
...
重新激活服务:
public class ReactivationService extends JobIntentService {
public static final int JOB_ID = 0x01;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, ReactivationService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
Log.i("In" , "onHandleWork()");
....
NotificationService.setNotificationServiceAlarm(this, new Prefs(this).getNotifs());
}
}
启动接收器:
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.i("In" , "getAction()");
ReactivationService.enqueueWork(context, intent);
}
else
Log.i("No" , "Boot");
}
}
升级接收器:
public class UpgradeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_MY_PACKAGE_REPLACED)) {
Log.i("In" , "getAction()");
ReactivationService.enqueueWork(context, intent);
}
else
Log.i("No" , "Upgrade");
}
}
现在我的问题是,ACTION_MY_PACKAGE_REPLACED 工作正常并显示了通知,但 ACTION_BOOT_COMPLETED 没有显示通知。可能是什么原因,因为我为两个接收者使用相同的服务。
从Android开始 O,你不能从后台应用程序启动服务而不会出现异常:
java.lang.IllegalStateException: Not allowed to start service Intent (my_service) : app is in background
如果您仍然需要在设备启动时启动服务,您现在可以使用新的 JobIntentService。
将您的 IntentService
更改为 JobIntentService
:
public class ReactivationService extends JobIntentService {
public static final int JOB_ID = 0x01;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, ReactivationService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
// do your stuff here
}
}
在您的 StartupReceiver
中按如下方式使用它:
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
ReactivationService.enqueueWork(context, new Intent());
}
}
}
在清单中声明您的服务:
<service android:name=".ReactivationService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
就是这样。这将直接启动服务(在 O 之前的平台上 运行 时)或将其作为作业排队(在 O 及更高版本上 运行 时)。不管是什么平台,你在enqueueWork
中传递的一切,最终都会出现在onHandleWork
.