Поскольку вы упомянули, что AlarmManager и другие не работают для вас, я протестировал то, что вы пытаетесь достичь с помощью JobScheduler.
Это сработало для меня и сработало даже после удаления приложения из недавнего список приложений. Я попробовал это на эмуляторе Android 10.
Вы запросили темы / ссылки для изучения в качестве ответа. Итак, сначала я упомяну ссылки, которые я использовал.
Вот кодовая лаборатория JobScheduler, и она действительно полезна: https://codelabs.developers.google.com/codelabs/android-training-job-scheduler/
Вот хорошая ссылка о создание нескольких запланированных заданий: https://android-developers.googleblog.com/2017/10/working-with-multiple-jobservices.html
Вот что я попробовал.
NotificationJobService.kt
private const val NOTIF_CHANNEL_ID = "primary_notification_channel"
private const val NOTIF_CHANNEL_NAME = "Job Service notification"
class NotificationJobService : JobService() {
override fun onStartJob(params: JobParameters?): Boolean {
// Get Notification Manager
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Create Notification Channel if device OS >= Android O
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel(NOTIF_CHANNEL_ID, NOTIF_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT).let {
notificationManager.createNotificationChannel(it)
}
}
// Create PendingIntent with empty Intent
// So this pending intent does nothing
val pendingIntent = PendingIntent.getActivity(this, 0, Intent(), PendingIntent.FLAG_ONE_SHOT)
// Configure NotificationBuilder
val builder = NotificationCompat.Builder(this, NOTIF_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Title")
.setContentText("Message")
.setAutoCancel(true)
.setContentIntent(pendingIntent)
// Make the Notification
notificationManager.notify(0, builder.build())
// False to let system know that the job is completed by the end of onStartJob(),
// and the system calls jobFinished() to end the job.
return false
}
override fun onStopJob(params: JobParameters?): Boolean {
// True because if the job fails, you want the job to be rescheduled instead of dropped.
return true
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Job ID must be unique if you have multiple jobs scheduled
var jobID = 0
// Get fake user set time (a future time 1 min from current time)
val ( userSetHourOfDay, userSetMinute ) = getMockUserSetTime()
val timeToWaitBeforeExecuteJob = calculateTimeDifferenceMs(userSetHourOfDay, userSetMinute)
(getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler).run {
schedule(
JobInfo.Builder(
jobID,
ComponentName(baseContext, NotificationJobService::class.java)
)
// job execution will be delayed by this amount of time
.setMinimumLatency(timeToWaitBeforeExecuteJob)
// job will be run by this deadline
.setOverrideDeadline(timeToWaitBeforeExecuteJob)
.build()
)
}
}
// Returns a pair ( hourOfDay, minute ) that represents a future time,
// 1 minute after the current time
private fun getMockUserSetTime() : Pair<Int, Int> {
val calendar = Calendar.getInstance().apply {
// add just 1 min from current time
add(Calendar.MINUTE, 1)
}
return Pair(calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE))
}
// Calculate time difference relative to current time in ms
private fun calculateTimeDifferenceMs(hourOfDay: Int, minute: Int) : Long {
val now = Calendar.getInstance()
val then = (now.clone() as Calendar).apply {
set(Calendar.HOUR_OF_DAY, hourOfDay)
set(Calendar.MINUTE, minute)
}
return then.timeInMillis - now.timeInMillis
}
}
Я использовал ограничения setMinimumLatency(timeToWaitBeforeExecuteJob)
и setOverrideDeadline(timeToWaitBeforeExecuteJob)
при планировании задания, чтобы задание было выполнено точно в то время, когда мы хотим его запустить.
Я запустил приложение один раз, go назад и удалил приложение из списка последних приложений. Затем я приостановил устройство и через 1 минуту услышал звук уведомления. Когда я возобновил работу устройства и проверил, там было ожидаемое уведомление.
Вам также следует рассмотреть ответ Ремона Шехатты . Потому что кажется, что WorkManager располагается поверх JobScheduler и AlarmManager и выбирает правильный, основываясь на уровне API устройства. Поэтому может быть лучше использовать WorkManager, если вы ориентируетесь на уровни API старше 21 года. Но, как вы упомянули, что AlarmManager не работает для вас, вам следует поэкспериментировать и выбрать правильный.
Пожалуйста, обновите нам с вашими выводами.