0

I have asked a question about periodic work here: How can a closed application receive periodic broadcasts?. The answer has been to use WorkManager and this has been a great solution on Android 9.

On another device using Android 10 the solution of this former question does not work anymore. This seems to be a common problem. The question here has been upvoted a lot, but its single answer is not accepted and it also didn't help me: WorkManager not working when app killed in Android 10 although working fine till version 9 (Pie).

Therefore I would like to formulate a specific problem for Android 10. Does anyone know how to solve it?

  1. Create an empty activity in AndroidStudio with File->New->New Project...->Empty Activity->Language: Java, SDK: API 28.
  2. Add a class MyWorker with the following content:
package org.test.myapplication;

import android.content.Context;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class MyWorker extends Worker
{
    public MyWorker(@NonNull Context context, @NonNull WorkerParameters params)
    {
        super(context, params);
    }

    @Override
    public Result doWork()
    {
        Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                // Play tone to show that the worker is working
                ToneGenerator toneGenerator = new ToneGenerator(AudioManager.STREAM_MUSIC, 200);
                        toneGenerator.startTone(ToneGenerator.TONE_CDMA_EMERGENCY_RINGBACK, 1000);

                // Also display some message
                Toast.makeText(getApplicationContext(), "Testing", Toast.LENGTH_SHORT).show();
            }
        }, 1000);

        // Indicate whether the work finished successfully with the Result
        return Result.success();
    }
}
  1. Modify the class MainActivity to have the following content:
package org.test.myapplication;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
import androidx.work.WorkRequest;

import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        WorkRequest workRequest =
                new PeriodicWorkRequest.Builder(MyWorker.class, 15, TimeUnit.MINUTES).build();

        WorkManager.getInstance(this).enqueue(workRequest);
    }
}
  1. Install and run the application. The tone from MyWorker::doWork is played and the respective toast is displayed.
  2. Now swipe the activity up to close it.

Expectation: The periodic work should continue to be executed like it has been on Android 9.

Actual behaviour: Nothing happens anymore. The WorkManager has obviously been stopped.

Question: How can I modify the example to work on Android 10?

Benjamin Bihler
  • 1,612
  • 11
  • 32
  • "The periodic work should continue to be executed like it has been on Android 9" -- not necessarily. Device manufacturers have screwed up their task management on Android 9 and earlier as well. Also note that your test is not particularly reliable (process might end or `Handler` might be GC'd before the time elapses, might have problems from trying to display a `Toast` without an `Activity`, etc.). Use Logcat to log a message before returning `Result.success()`. – CommonsWare Feb 04 '21 at 12:05
  • And, rolling all the way back to your premise, `WorkManager` is not guaranteed to keep your process around to be able to receive broadcasts. My reference to polling using `WorkManager` was not to receive broadcasts, but to poll for some system state. – CommonsWare Feb 04 '21 at 12:06
  • @CommonsWare But in the example given here, I do not try to receive broadcasts. I play a tone and display a toast. "Polling some system state" should be equivalent at least to playing tones, shouldn't it. So when my `WorkManager` cannot reliably play tones when the activity is closed, what can I use instead? – Benjamin Bihler Feb 04 '21 at 13:38
  • My device is a Samsung Tab S4. Do you really think that the same app might work on another device? – Benjamin Bihler Feb 04 '21 at 13:39
  • ""Polling some system state" should be equivalent at least to playing tones, shouldn't it" -- since `doWork()` is already running on a background thread, you would not need `Handler`. I do not know why your example is using a `Handler` or playing tones. Use Logcat. "So when my WorkManager cannot reliably play tones when the activity is closed, what can I use instead?" -- I would start by using Logcat instead of playing tones. Then, I would make sure that I am on the latest production version of the `WorkManager` library. – CommonsWare Feb 04 '21 at 13:42
  • Then, if you still do not see evidence of your `doWork()` getting called every 15 minutes after the task removal, create a project that reproduces those findings and file a bug report. In the end, even `WorkManager` will be unreliable on some devices. A Samsung is fairly mainstream, though, and so the team behind `WorkManager` should be, um, working to get it to be reliable there. – CommonsWare Feb 04 '21 at 13:44
  • @CommonsWare Your comments have been very helpful. Thank you very much. – Benjamin Bihler Feb 05 '21 at 15:32

1 Answers1

0

There has been nothing wrong with the code or the project setup. My device has been in power saving mode and this obviously has prevented the periodic WorkManager tasks when the activity had been closed. Leaving power saving mode has solved the problem.

Benjamin Bihler
  • 1,612
  • 11
  • 32