Work Manager on Chinese ROMs like Xiaomi and Oppo, when under battery optimization, increase the scheduled delay of work by several hours., however, I have noticed some apps
This is the more elaborate response. As mentioned by the others, yes work manager doesn't work properly. It may do the work with a delay. some times 15 minutes and in some cases 10 to 12 hours. There is no workaround for that. But, if you want to do a task on a specific hour and date, there is a way to do that. you should use an alarm manager, with a broadcast receiver and a foreground service.
So this is the IntentService class:
public class NotificationService extends IntentService {
//In order to send notification when the app is close
//we use a foreground service, background service doesn't do the work.
public NotificationService() {
super("NotificationService");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
sendNotification(intent);
}
private void sendNotification(Intent intent){
Context context = NotificationService.this;
PendingIntent pIntent = PendingIntent.getActivity(context, 0, intent, 0);
Notification.Builder builder = new Notification.Builder(context)
.setTicker("Notification")
.setContentTitle("Important Message")
.setContentText("This is an example of a push notification using a Navigation Manager")
.setSmallIcon(R.drawable.ic_add)
.setContentIntent(pIntent);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
String channelId = "Your_channel_id";
NotificationChannel channel = new NotificationChannel(
channelId,
"Reminder to remind to review your notes",
NotificationManager.IMPORTANCE_HIGH);
channel.setDescription("Hello Dear friends"); //this is to test what this is
notificationManager.createNotificationChannel(channel);
builder.setChannelId(channelId);
}
Notification notification = builder.build();
notification.flags = Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
}}
this is the Receiver class:
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("SHIT","YESSSS");
Intent service = new Intent(context, NotificationService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(service);
} else {
context.startService(service);
}
}}
and this is where I set the the Alarm on a specific date:
private void setNotificationAlarm(){
//Alarm Manager
Calendar time = Calendar.getInstance();
time.set(Calendar.HOUR_OF_DAY,16);//set the alarm time
time.set(Calendar.MINUTE, 50);
time.set(Calendar.SECOND,0);
AlarmManager am =(
AlarmManager)getContext().getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(getActivity(), AlarmReceiver.class);
i.setAction("android.intent.action.NOTIFY");
PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, i,
PendingIntent.FLAG_ONE_SHOT);
// am.setRepeating(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), 1000 * 60 * 10,
pi); // Millisec * Second * Minute
if (Build.VERSION.SDK_INT >= 23){
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pi);
}
else{
am.set(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pi);
}
}
And of course you have to declare your Service and BroadcastRecevier in the manifest. This works like a charm.
Xiomi MiUi 11 (chinese version of firmware) Work Manager very badly by default and runs in random order several times and after a few hours it just stops working.Further nothing happens. To solve the problem, I took 2 steps
1. Settings->Battery & perfomance -> App battery saver -> Select you application -> No restrictions
2. Settings -> Apps -> Permissions -> Autostart -> Add your application to autostart
After I added to Autostart
and No restrictions battery
. I rebooted the device and it worked correctly with Work Manager. I think that on Chinese devices that have heavily modified android, it is only possible to manually add launch permissions.
Similar questions have best asked in the past here and here.
This has been also asked on WorkManager's issue tracker: are the Chinese manufacturers (Huawei, Oppo, Xiaomi...) supported?
To summarize: this is a known issue with some Android OEM that heavily modify this part of Android for battery optimization. There's nothing that WorkManager can do to solve this issue.
Aside having you application added to the whitelist, you can really only report the issue:
You can take a look at the exact instruction to add to your app in a whitelist for the different devices on the amazing website don't kill my app, also I've seen this library on github that can be useful to simplify the process for your users.
So, turns out the solution to keep the jobs running on time is to enable auto-start and disable battery optimization for the devices. Guiding your users to do so is inconvenient but as of now, this is what can be done!
This is a known issue and, as commented in this other bug on Google's issuetracker, there's not much that WorkManager can do in these cases.if a device manufacturer has decided to modify stock Android to force-stop the app, WorkManager will stop working (as will JobScheduler, alarms, broadcast receivers, etc.). There is no way to work around this. Some device manufacturers do this, unfortunately, so in those cases WorkManager will stop working until the next time the app is launched. Also you can try with the StartForgoundService() and until and unless your work is not done you need to show notification in forground.
WorkManager is intended for tasks that are deferrable—that is, not required to run immediately—and required to run reliably even if the app exits or the device restarts. For example
WorkManager is not intended for in-process background work that can safely be terminated if the app process goes away or for tasks that require immediate execution. Please review the background processing guide to see which solution meets your needs.
There are two types of work supported by WorkManager: OneTimeWorkRequest and PeriodicWorkRequest`.
So would that be responsible for keeping the app alive by the battery optimizer?
A WorkRequest for repeating work. This work executes multiple times until it is cancelled, with the first execution happening immediately or as soon as the given Constraints are met. The next execution will happen during the period interval; note that execution may be delayed because WorkManager is subject to OS battery optimizations, such as doze mode.
I also noticed, that after I force stopped that app, after 24 hours it started working again, but how is that possible?
See PeriodicWorkRequest.Builder
- Creates a PeriodicWorkRequest to run periodically once within the flex period of every interval period. See diagram below. Note that flex intervals are ignored for certain OS versions (in particular, API 23). The flex period begins at
repeatInterval - flexInterval
to the end of the interval. The repeat interval must be greater than or equal to PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS and the flex interval must be greater than or equal to PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS.