问题
I am trying to run a service on OREO device and service get started as it listens to android.intent.action.BOOT_COMPLETED intent.
Below is Boot Received Broadcast Reciever class:
public class ConnectionBOOTReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
MyIntentService.enqueueWork(context, new Intent());
}
}
Below is my IntentService Class:
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
}
}
As I know there is some Background limitation I have to create two background services one is Foreground and other one runs in the background.
Background Service Code:
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;
}
}
}
Foreground Service code :
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());
}
}
Below is exception which i am getting :
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)
How can I start my service from Boot Broadcast receiver? How can I make sure that it should keep running always?
回答1:
Since Android O Apps can no longer run Background Services while the App is in the Background. You will need to either update to a foreground service or migrate to jobs. I recommend the Evernote Android Job library to simplify working with Jobs and backwards compatibility.
回答2:
Yes. You can use the foreground service temporally to run background service.
I attached my code as below.
This is BOOT_COMPLETE BroadcastReceiver class.
public class BootCompleteReceiver extends BroadcastReceiver {
private static final String TAG = "BootCompleteReceiver";
@Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent i = new Intent(context, TempForegroundService.class);
context.startForegroundService(i);
} else {
Intent i = new Intent(context, BackgroundService.class);
context.startService(i);
}
}
}
This is TempForegroundService class.
public class TempForegroundService extends Service {
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String NOTIFICATION_CHANNEL_ID = "Your Package Name";
String channelName = "Your Channel Name";
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.ic_launcher)
.setContentTitle("App is running in background")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(2, notification);
startService(new Intent(this, BackgroundService.class));
stopForeground(true);
stopSelf();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
And this is BackgroundService class.
public class BackgroundService extends Service {
public final static String TAG = "BackgroundService";
public SyncService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Add your code
return START_STICKY;
}
}
Please don't forget to add permissions and define services and receiver.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<service
android:name=".BackgroundService"
android:enabled="true"
android:exported="false" />
<service
android:name=".TempForegroundService"
android:enabled="true"
android:exported="false" />
<receiver android:name=".BootCompleteReceiver">
<intent-filter>
<action android:name="android.intent.action.REBOOT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
来源:https://stackoverflow.com/questions/53170250/android-service-not-getting-start-from-jobintentservice-on-boot