Search code examples
androidpush-notificationandroid-workmanagerbackground-service

WorkManager stops scheduling periodic Worker after the app closes


maybe this is yet another question about WorkManager, but I really can't find a solution...

I'm trying, as the title suggests, to run a periodic work every 15 minutes. Actually in the worker I'm polling some data every minute. After every poll, every almost 1 second I check if the worker is being stopped and if so return, otherwise keep waiting until 1 minute is reached and poll data again.

According to the documentation this should work and indeed it is, until I kill the app from the recent app screen.

Here is the code:

package com.qsea.app.cordova;

import android.content.Context;

import android.os.SystemClock;

import android.util.Log;

import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class ServerListenerWorker extends Worker {

    public static final String TAG = "ServerListenerWorker";

    public ServerListenerWorker(
        Context appContext,
        WorkerParameters workerParams
    ) {
        super(appContext, workerParams);
    }

    @Override
    public Result doWork() {

        Log.d(TAG, "Doing work");

        final long startTime = SystemClock.elapsedRealtime();
        final int maxDelta = 840000; // 14 minutes

        while (true) {
            // I did this to stop this worker until 15 minutes
            // and then let the next worker run
            if (SystemClock.elapsedRealtime() - startTime >= maxDelta) {
                break;
            }

            // Here I'm polling data, if the polling results in a failure
            // I return Result.retry()

            // It avoid waiting if it remains only 1 minute until the max time
            if (SystemClock.elapsedRealtime() - startTime >= (maxDelta - 60000)) {
                break;
            }
            for (int i = 0; i < 60; i++) {
                SystemClock.sleep(950);
                // Here it checks if it is stopped
                if (isStopped()) {
                    Log.d(TAG, "Detected stop"); // this is actually never reached
                    break;
                }
            }
        }
        return Result.success();
    }
}

And I do as following to start the work

Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(ServerListenerWorker.class, 15, TimeUnit.MINUTES)
    .addTag(serverListenerWorkerUID)
    .setConstraints(constraints)
    .build();
WorkManager.getInstance(cordova.getActivity()).enqueueUniquePeriodicWork(serverListenerWorkerUID, ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest);

I check the correct working of the worker by viewing the log of my server (If I receive the request it is working fine) and it seems to work ok until I close the app. Then it stops running the actual worker and never run a worker again until I reopen the app, where the work seems to be enqueued and resumes right after the app opening.

Am I doing something wrong in the initialization? I have also <service android:name=".ServerListenerWorker" android:permission="android.permission.BIND_JOB_SERVICE" /> in my AndroidManifest.xml

Is this expected behavior?

I read that chinese ROM have additional restriction to background services and I have a HUAWEI, which seems to be the worst in this. So could it be the device? And if so, how do Facebook, WhatsApp, Instagram and others manage this to work even in these devices?


Solution

  • Let's split this in two different problems.

    1. What are you doing in your workers is battery heavy and would be better if you use a foreground service that notifies the user that your application is running continuously in the background. You can also use WorkManager with the newly introduced support for long-running workers (that under the hood uses a foreground service). More on this in the documentation.

    2. If have a problem with a specific OEMs, please open an issue on the Android issuetracker as this maybe a CDD violation. Google can contact the OEM and request that they fix the ROM. This is going to take time, in the meanwhile, you can take a look at sites like don't kill my app to understand what are the constraints on a specific device and use a library like autostarter to help the user to navigate to the right setting.

    BTW, you don't need to be list your workers in the AndroidManifest.xml file