android - Android 服务在 BOOT 上没有从 JobIntentService 开始
问题描述
我正在尝试在 OREO 设备上运行服务,并且服务在侦听android.intent.action.BOOT_COMPLETED意图时启动。
下面是 Boot Received Broadcast Reciever 类:
public class ConnectionBOOTReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
MyIntentService.enqueueWork(context, new Intent());
}
}
下面是我的 IntentService 类:
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;
public class MyIntentService extends JobIntentService {
// Service unique ID
static final int SERVICE_JOB_ID = 997;
// Enqueuing work into this service.
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, MyIntentService.class, SERVICE_JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
onHandleIntent(intent);
}
private void onHandleIntent(Intent intent) {
startService(new Intent(this,MyBackgroundService.class));
//Handling of notification goes here
}
}
我知道有一些背景限制,我必须创建两个后台服务,一个是前台,另一个在后台运行。
后台服务代码:
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import java.util.Timer;
import java.util.TimerTask;
public class MyBackgroundService extends Service {
private static final String TAG = "MyBackgroundService";
public int counter = 0;
public MyBackgroundService() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "NotifyingDailyService", Toast.LENGTH_LONG).show();
Log.i("com.example.ss ", "NotifyingDailyService");
super.onStartCommand(intent, flags, startId);
startTimer();
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
// send new broadcast when service is destroyed.
// this broadcast restarts the service.
stoptimertask();
}
private Timer timer;
private TimerTask timerTask;
long oldTime = 0;
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
//schedule the timer, to wake up every 1 second
timer.schedule(timerTask, 1000, 1000); //
}
/**
* it sets the timer to print the counter every x seconds
*/
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
Log.i("in timer", "in timer ++++ " + (counter++));
}
};
}
/**
* not needed
*/
public void stoptimertask() {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer = null;
}
}
}
前台服务代码:
public class MyForegroundBackgroundService extends Service {
private Context context;
public static final String NOTIFICATION_CHANNEL_ID = "10001";
public MyForegroundBackgroundService() {
}
@Override
public void onCreate(){
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startMyOwnForeground();
else
startForeground(1, new Notification());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
context = this;
super.onStartCommand(intent, flags, startId);
Intent intent1 = new Intent(this, MyForegroundBackgroundService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent1, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Calendar cal= Calendar.getInstance();
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 30*1000, pintent);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void startMyOwnForeground(){
String NOTIFICATION_CHANNEL_ID = "com.example.simpleapp";
String channelName = "My Background Service";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setOngoing(true)
.setSmallIcon(R.mipmap.talentify_logo_red)
.setContentTitle("App is running in background")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(2, notification);
}
public void sendNotification(String message,Context context){
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.general_message_notfication);
remoteViews.setTextViewText(R.id.message,message);
Intent intent = new Intent();
intent = new Intent(context, HomeActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context,NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.mipmap.talentify_logo_red)
.setAutoCancel(true)
.setContentIntent(pIntent)
.setContent(remoteViews);
NotificationManager notificationmanager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
try {
long[] pattern = new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400};
builder.setVibrate(pattern);
builder.setSound(Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.notification_sound));
} catch (Exception e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
int importance = NotificationManager.IMPORTANCE_HIGH;
@SuppressLint("WrongConstant") NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "Urgent", importance);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.enableVibration(true);
notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
builder.setChannelId(NOTIFICATION_CHANNEL_ID);
notificationmanager.createNotificationChannel(notificationChannel);
}
notificationmanager.notify(0, builder.build());
}
}
以下是我得到的例外:
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=test.MyApplication/.service.MyBackgroundService }: app is in background uid UidRecord{7e9d561 u0a158 TRNB idle procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1536)
at android.app.ContextImpl.startService(ContextImpl.java:1492)
如何从 Boot Broadcast 接收器启动我的服务?我怎样才能确保它应该一直运行?
解决方案
由于 Android O 应用程序在后台时无法再运行后台服务。您将需要更新到前台服务或迁移到作业。我推荐 Evernote Android Job 库来简化 Jobs 的使用和向后兼容性。
推荐阅读
- caching - 缓存和缓存失效不起作用 GCP Cloud CDN
- swift - Swift - JSONSerialization 无效的 JSON
- facebook-graph-api - Facebook Graph API - 是否有用户 ID?我们想看看用户浏览了我们的每个页面多少次?
- powerbi - 周期的 PowerBI 动态过滤器
- kubernetes - Kubernetes 本地 PV 和 PVC 比实际磁盘大?
- c - 如何向 mingw-w64 添加自定义库(例如 glew)?
- hex - 如何将工作 URL 写入 Mifare Classic 1K
- ios - 使用没有内容的 URL 调用 QLPreviewControllerDelegate 的方法 didSaveEditedCopyOf
- conda - 存储在 .conda 文件夹中的默认 Conda 环境
- indexing - 根据其他列中定义的间隔索引 pyspark 列