Edit: I've now tried WorkManager
, and it seems to be hugely unreliable in timing as well. Sorry about that.
If you want to schedule a local notification that doesn't need extremely precise time, you're better off not using AlarmManager, as many Android phones will run it way too late, or never. Instead use WorkManager from androidx.
All this was explained awesomely by Josip Žitković in this blog.
First, schedule the notification whereever you want:
WorkRequest work = new PeriodicWorkRequest.Builder(MyWorker.class, 1, TimeUnit.DAYS)
.setInitialDelay(delay, TimeUnit.MINUTES)
.build()
;
WorkManager.getInstance(context).enqueue(work);
Now create MyWorker, that will be called to show the actual notification:
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.app.TaskStackBuilder;
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() {
Context context = this.getApplicationContext();
// Intent to start when notification is tapped
Intent notificationIntent = new Intent(context, MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
createNotificationChannel(context);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "my_channel")
.setContentTitle("hello, world")
// Only on api < 26, see createNotificationChannel otherwise
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Default sound, vibration etc
// Only on api < 26, see createNotificationChannel otherwise
.setDefaults(Notification.DEFAULT_ALL)
.setContentIntent(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(0, builder.build());
return Result.success();
}
/**
* This needs to be called at least once on android API >= 26 before creating a notification.
*/
public static void createNotificationChannel(Context context) {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("my_channel", "MyApp notifications", NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("They will wake you up in the night");
channel.enableVibration(true);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}