我正在使用PeriodicWorker对我的应用程序数据进行每日备份,即将mu本地数据上传到云存储服务。 但是,当我首先使用
setForegroundAsync(foregroundInfo);
时,会显示警告
(startForegroundService() not allowed due to mAllowStartForeground false: service com.mydomain/androidx.work.impl.foreground.SystemForegroundService
)在这个过程中,它给了我下面的错误
Unable to stop foreground service
android.app.BackgroundServiceStartNotAllowedException: Not allowed to start service Intent { act=ACTION_STOP_FOREGROUND cmp=com.mydomain/androidx.work.impl.foreground.SystemForegroundService }: app is in background uid UidRecord{dff373e u0a386 TRNB bg:+3m49s885ms idle change:procadj procs:0 seq(7594403,7591739)} caps=------
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1945)
at android.app.ContextImpl.startService(ContextImpl.java:1900)
at android.content.ContextWrapper.startService(ContextWrapper.java:825)
at androidx.work.impl.Processor.stopForegroundService(Processor.java:425)
at androidx.work.impl.Processor.stopForeground(Processor.java:303)
at androidx.work.impl.WorkerWrapper.resolve(WorkerWrapper.java:464)
at androidx.work.impl.WorkerWrapper.resetPeriodicAndResolve(WorkerWrapper.java:577)
at androidx.work.impl.WorkerWrapper.handleResult(WorkerWrapper.java:480)
at androidx.work.impl.WorkerWrapper.onWorkFinished(WorkerWrapper.java:358)
at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:335)
at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012)
“有趣”的部分是该过程运行得非常好,所有数据都完美地复制到云端,除了未显示的通知之外没有任何问题。
有人知道如何在应用程序处于后台时显示通知吗?
这是我的工人代码。
public class DatabaseCloudBackupWorker extends Worker {
public static final String TAG = DatabaseCloudBackupWorker.class.getName();
@Override
public Result doWork() {
Result result = Result.failure();
Log.i(TAG, "Starting Database Backup");
this.showProgressNotification();
try {
uploadData()
result = Result.success();
} catch (Exception e) {
Log.e(TAG, "Error")
}
return result;
}
private void showProgressNotification() {
Log.i(TAG, "Showing Database Backup Progress Notification");
Notification notification = this.newProgressNotification();
ForegroundInfo foregroundInfo;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
foregroundInfo = new ForegroundInfo(PROGRESS_NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
} else {
foregroundInfo = new ForegroundInfo(PROGRESS_NOTIFICATION_ID, notification);
}
this.setForegroundAsync(foregroundInfo);
}
private Notification newProgressNotification() {
Notification notification = new NotificationCompat.Builder(MyApp.getAppContext(), MyNotificationManager.CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setOnlyAlertOnce(true)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setProgress(0, 0, true)
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
.setContentTitle("Database Backup")
.setContentText("Database Backup in Progress")
.build();
return notification;
}
}
这是我的清单会话,我在其中设置了前台服务的类型
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
tools:node="merge" />
这是我创建PeriodicWorkRequest的地方
// Creating Work Request
Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.UNMETERED).build();
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(DatabaseCloudBackupWorker.class, 1, TimeUnit.DAYS)
.setInitialDelay(initialDelayInMinutes, TimeUnit.MINUTES)
.addTag(DatabaseCloudBackupWorker.TAG_PERIODIC_WORKER)
.setConstraints(constraints)
.setInputData(inputData)
.build();
//
WorkManager workManager = WorkManager.getInstance(MyApp.getAppContext());
Log.i(TAG, "Enqueuing DatabaseCloudBackupWorker");
Operation operation = workManager.enqueueUniquePeriodicWork(DatabaseCloudBackupWorker.NAME_PERIODIC, ExistingPeriodicWorkPolicy.UPDATE, workRequest);
使用以下代码获取通知。
您必须在 Android 8.1 及更高版本中创建通知通道。
private static final int NOTIFICATION_ID = 1;
private static final String CHANNEL_ID = "MyChannelId";
// Create a notification channel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "My Channel", NotificationManager.IMPORTANCE_LOW);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
Notification notification = buildNotification();
startForeground(NOTIFICATION_ID, notification);
@RequiresApi(api = Build.VERSION_CODES.M)
private Notification buildNotification() {
Intent fullScreenIntent = new Intent(this, HomeActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
fullScreenIntent, PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("Title")
.setContentText("Text")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
// Use a full-screen intent only for the highest-priority alerts where you
// have an associated activity that you would like to launch after the user
// interacts with the notification. Also, if your app targets Android 10
// or higher, you need to request the USE_FULL_SCREEN_INTENT permission in
// order for the platform to invoke this notification.
.setFullScreenIntent(fullScreenPendingIntent, true);
return notificationBuilder.build();
}