Search code examples
androidandroidxworkerandroid-workmanager

How can I access objects from my Activity in a Worker? (to periodically change a notification)


I would like to periodically change a notification's text in a Worker. (androidx.work.WorkManager)

My MainActivity looks like this

public class MainActivity extends AppCompatActivity {

    ...

    private NotificationManagerCompat notificationManagerCompat;
    private NotificationCompat.Builder notificationBuilder;

    ...

    private void startNotification() {

        ...

        notificationBuilder =
                    new NotificationCompat.Builder(getApplicationContext(), warnotifier_notification_channel)
                            .setSmallIcon(R.drawable.notification_icon)
                            .setContentTitle(notificationTitle)
                            .setContentText(notificationText)
                            .setContentIntent(pendingIntent)
                            .setAutoCancel(true)
                            .setPriority(NotificationCompat.PRIORITY_LOW)
                            .setOngoing(true);

        notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());

        notificationManagerCompat.notify(1, notificationBuilder.build());

        PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(NotificationWorker.class, PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS, TimeUnit.MILLISECONDS)
                    .addTag(workTag)
                    .build();

        WorkManager.getInstance(getApplicationContext()).enqueue(periodicWorkRequest);
    }

   ...

}

and my Worker looks like this

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

    @NonNull
    @Override
    public Result doWork() {
        String notificationText = "Time: " + calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND);
        notificationBuilder.setContentText(notificationText);
        notificationManagerCompat.notify(1, notificationBuilder.build());
        return Result.success();
    }
}

Unfortunately, Android does not allow me to put the Worker as a nested class in my MainActivity, and therefore I can't access the NotificationManagerCompat and NotificationCompat.Builder instances like above.

I know I can pass simple data with periodicWorkRequest.setInputData(inputData) to the Worker but I don't think that helps ...

Any ideas? Thanks in advance.


Solution

  • Unfortunately, Android does not allow me to put the Worker as a nested class in my MainActivity, and therefore I can't access the NotificationManagerCompat and NotificationCompat.Builder instances like above.

    Why you need to add your NotificationWorker class within the MainActivity?

    As you mentioned you just want to access NotificationManagerCompat and NotificationCompat.Builder from the Worker class and there is no restriction to that, so to build your notification you already have a context passed to Worker class constructor, and also you can still call getApplicationContext() from the Worker class. I have tested that without any problem.

    Hope that helps. I am welcome if you have any queries.

    Update

    In my Worker class I wanted to access the notificationManagerCompat and notificationBuilder instances I created in MainActivity.

    You don't have to create notificationManagerCompat & notificationBuilder instances in MainActivity, you can normally create them in NotificationWorker

    Here is a demo from your code

    public class NotificationWorker extends Worker {
        private final NotificationManagerCompat notificationManagerCompat;
        private final NotificationCompat.Builder notificationBuilder;
    
        public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters params) {
            super(context, params);
    
            PendingIntent pendingIntent = PendingIntent.getActivity
                    (context, 0, new Intent(context, MainActivity.class),
                            PendingIntent.FLAG_UPDATE_CURRENT);
    
                            notificationBuilder =
                    new NotificationCompat.Builder(getApplicationContext(), warnotifier_notification_channel)
                            .setSmallIcon(R.drawable.notification_icon)
                            .setContentTitle(notificationTitle)
                            .setContentText(notificationText)
                            .setContentIntent(pendingIntent)
                            .setAutoCancel(true)
                            .setPriority(NotificationCompat.PRIORITY_LOW)
                            .setOngoing(true);
    
            notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
    
        }
    
        @NonNull
        @Override
        public Result doWork() {
            Calendar calendar = new GregorianCalendar();
            String notificationText = "Time: " + calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND);
            notificationBuilder.setContentText(notificationText);
            notificationManagerCompat.notify(1, notificationBuilder.build());
            return Result.success();
        }
    }
    

    And you can get notificationTitle, notificationText from res/string using R.string.XX, and notification_icon from res/drawable using R.drawable.XX.

    With this you can use NotificationManagerCompat and NotificationCompat.Builder from your Worker, all you need just a context, no need to activity.

    hope this answers your question.