I have home screen widget, which has a simple AppWidgetProvider
and JobIntentService
, where I do all the work.
Problem is - it works kind of randomly. Sometimes it does, sometimes it doesnt - weirdest thing is, I can see in the log, that on each widget update enqueueWork
method of JobIntentService
is ALWAYS called, but onHandleWork
method only sometimes.
(I have found there is strong, though not 100% correlancy with battery optimization. If I turn of "Manage apps automatically", then it 99% works reliably. If it is turned on, its like flipping a coin. Sometimes it does, sometimes it doesnt. Best to ilustrate behavior would be this short simple video
This is my code (Widget provider):
public class MyWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Log.v("aaa", "onUpdate");
// super.onUpdate(context, appWidgetManager, appWidgetIds);
// update in my own Service (to avoid ANR)
Intent intent = new Intent(context, MyJobIntentService.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
MyJobIntentService.enqueueWork(context, intent);
}
@Override
public void onReceive(Context context, Intent intent) {
Log.v("aaa", "onReceive");
super.onReceive(context, intent);
}
}
And this is my service (JobIntentService) where I do all work:
public class MyJobIntentService extends JobIntentService {
public static final int JOB_ID = 1;
public static void enqueueWork(Context context, Intent work) {
Log.v("aaa", "enqueueWork: ");
enqueueWork(context, MyJobIntentService .class, JOB_ID, work);
}
@Override
protected void onHandleWork(Intent intent) {
Log.v("aaa", "onHandleWork: ");
}
}
This is the same thing that is happening to me. What I've found out is that in the android documentation, it says:
When running as a pre-O service, the act of enqueueing work will generally start the service immediately, regardless of whether the device is dozing or in other conditions. When running as a Job, it will be subject to standard JobScheduler policies for a Job with a JobInfo.Builder.setOverrideDeadline(long) of 0: the job will not run while the device is dozing, it may get delayed more than a service if the device is under strong memory pressure with lots of demand to run jobs.
This means in Android O and above devices, it is not guaranteed that the jobIntentService starts immediately, but start with the delay depending on the device's condition. But, some phone manufacturers are deliberately canceling the job for better battery life (Like OnePlus). So the job is never called.
The workaround that I used is to create a LOW_IMPORTANCE foreground service and call it using:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(startIntent);
} else {
context.startService(startIntent);
}
But the drawback is that the notification is shown for a small duration till the work is complete.
Maybe google should put some restrictions on the device manufacturers on how to manage the background apps.