3

Similar questions: service not starting on oreo in app widgetusing The closest to my question is Widget freezes after some time but is unanswered.

I have a simple widget button that should send a notification when pressed. It doesn't work when:

  1. I clear the app from recents just after opening the app on install
  2. randomly stops working sometimes (sometimes all the clicks are triggered together after I open the app again leading to a bunch of notifications getting fired together.)

From what all I have read so far, it looks to me as if the PendingIntent is getting cleared.

The code is mostly taken from the official app widget guide except for starting a Service instead of Activity.

WidgetProvider:

public class WidgetProvider extends AppWidgetProvider {

    @RequiresApi(api = Build.VERSION_CODES.O)
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        final int N = appWidgetIds.length;

        for (int appWidgetId : appWidgetIds) {
            Intent myIntent = new Intent(context, WidgetService.class);
            myIntent .setAction("SOME_UNIQUE_ACTION");
            PendingIntent pendingIntent = PendingIntent.getForegroundService(context, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

WidgetService:

public class WidgetService extends JobIntentService {

    public WidgetService() {
        super();
    }

    @Override
    protected void onHandleWork(@Nullable Intent i) {
        Utils.sendNotification(); // this method works and is tested
    }
}

I tried both answers from here, Broadcast method didn't work and looked indirect as well, so I added #onCreate implementation to call startForeground, which didn't work either.

@Override
    public void onCreate() {
        super.onCreate();

        Utils.sendNotification();
        try {
            startForeground(1, notification);
        } catch (Error e) {
            Log.i(TAG, e.toString());
        }
    }
}

How do I get a button that will start a service reliably every time? Any help appreciated.

  • 1
    Stop clearing the app from the overview screen. On some devices, that will indeed cancel your outstanding `PendingIntent` objects, and there is nothing that you can do about that. In addition, `JobIntentService` is not designed to be used this way -- I am surprised that it works at all, particularly on Android 8.0 and higher. Use a regular `Service`. – CommonsWare Aug 30 '20 at 23:18
  • @CommonsWare Is there any way I can reset it? Is it possible to somehow listen to a system broadcast sent after clearing the app and then calling `onUpdate()` to reset the PendingIntent? Thanks for pointing out about `JobIntentService`. – Anand Goswami Aug 30 '20 at 23:23
  • 1
    Not really. On some devices, the manufacturer has decided to have clearing the app do the equivalent of a "Force Stop" from your app's screen in the Settings app. When that happens, nothing of your app will run again, until some explicit `Intent` is used to start one of your components. Typically, this will be the user navigating to your app from the launcher. – CommonsWare Aug 30 '20 at 23:26
  • Can this be done at least for Android One phones? – Anand Goswami Aug 30 '20 at 23:28
  • 2
    Well, I would start by replacing the `JobIntentService` with a `Service`, and see if things improve. `JobIntentService`, on Android 8.0 and higher, really schedules a job with `JobScheduler`, rather than doing the work directly. It may be that you are seeing jobs getting canceled, and the task getting cleared is not doing a full "Force Stop". In that case, you may have better luck with a regular `Service`. – CommonsWare Aug 30 '20 at 23:31
  • @CommonsWare thanks a lot! You were right. A `Service` instead of `JobIntentService` should be used in case of widgets to execute small widget tasks quickly. I am not sure if I can do without a foreground Service because there appears to be a restriction on starting a service from background if the app has not been active. I didn't try it out either as I think a Foreground service is more reliable for my case. – Anand Goswami Aug 31 '20 at 11:37
  • 2
    "there appears to be a restriction on starting a service from background if the app has not been active" -- you have a short window of time to be able to run in the background. If you use a `getService()` `PendingIntent`, it should be one minute. But, I am glad that you are having better luck with a regular `Service`. `JobIntentService` is mostly (if not exclusively) for cases where you cause it to run yourself, via an `enqueueWork()` call, not for where something else will try to run it just via an `Intent`. – CommonsWare Aug 31 '20 at 11:50

0 Answers0