How can I send scheduled notifications in Android Studio? I got this task: I want to get notifications at the some chosen time of the day every day. I can easily get them when app is alive, but when its closed notifications don't come up.
I've already tried JobScheduler, AlarmManager and WorkManager and none of these didn't work well. My project runs at minimum SDK 26 (Android Oreo). Target SDK is 30. Last code version looks like that:
AlertReceiver.java
public class AlertReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
intent = new Intent(context, NotificationService.class);
context.startService(intent);
}
}
NotificationService.java
public class NotificationService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
showNotifications();
return Service.START_STICKY;
}
private void showNotifications(){
NotificationHelper notificationHelper = new NotificationHelper(getApplicationContext());
NotificationCompat.Builder nb;
nb = notificationHelper.getChannelNotification("Title", "Description");
notificationHelper.getManager().notify(123, nb.build());
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
I schedule the alert like so:
...
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hours);
calendar.set(Calendar.MINUTE, minutes);
AlarmManager alarm_manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlertReceiver.class);
PendingIntent pending_intent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarm_manager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pending_intent);
```
The problem is that from Android 8 calling startService
from the background is not allowed:
In this code:
public class AlertReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
intent = new Intent(context, NotificationService.class);
context.startService(intent);
}
}
You can change from:
context.startService(intent);
To:
ContextCompat.startForegroundService(getApplicationContext(), intent)
And put this in your Manifest:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
This will at least allow your service to run from the background in your current implementation.
You then have 5 seconds to call startForeground()
in your Service
and post a Notification
that lets the user know that your service is running or it will be terminated.
Also for what you are trying to do, I think you will get a better result with:
setExactAndAllowWhileIdle
Or
setAlarmClock
setExact
does not work as the name implies. All the AlarmManager documentation needs to be read carefully and I would suggest studying "doze" in detail before attempting any Service
implementations that rely on timing.