Как запланировать и отправить уведомление даже после того, как пользователь удалит приложение из последних приложений? - PullRequest
0 голосов
/ 02 мая 2020

Мое приложение простое

  1. Отнимите время у пользователя (я знаю, как это сделать)

  2. Расписание Уведомление (я знаю как отправить уведомление)

  3. Теперь я просто хочу знать, как я могу отправить это уведомление, даже если пользователь удаляет его из последних приложений.

Пробные решения - AlarmManager, BroudcastReceiver, Service, Intent Service,

Но все они работают только тогда, когда приложение присутствует в ОЗУ (список последних приложений Mobile).

Как это сделать просто скажи мне топи c. Мне не нужен код Я буду изучать это.

Ответы [ 2 ]

3 голосов
/ 02 мая 2020

вы можете использовать WorkManger для планирования задач.

API WorkManager позволяет легко планировать отложенные, асинхронные задачи, которые должны запускаться даже при выходе из приложения или перезапуске устройства.

check Документация Google здесь .

для уведомлений вы можете отправить уведомление в своем классе менеджера работы. узнать больше здесь .

этих подсказок должно быть достаточно. дайте мне знать, если вам нужно больше разъяснений.

1 голос
/ 02 мая 2020

Поскольку вы упомянули, что 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 не работает для вас, вам следует поэкспериментировать и выбрать правильный.

Пожалуйста, обновите нам с вашими выводами.

...