JobService 在 Android 上使用 Switch 小部件触发通知

JobService to fire Notification by using Switch widget on Android

我有一个带有 Switch 的应用程序必须启动我的 JobService。我在Switch的setOnCheckedChangeListener中调用了两种方法,一种用于注册作业,一种用于注销作业。 它似乎可以工作,就像调试显示一样,但是 onStartJob 中的后台工作。我错过了什么?

MemoNotificationService.kt

class MemoNotificationService : JobService() {

    companion object {
        const val TAG = "MemoPush"
        const val serviceId = 4242
    }


    override fun onStartJob(params: JobParameters?): Boolean {
        doBackgroundWork(params)
        return true
    }

    private fun doBackgroundWork(params: JobParameters?) {
        CoroutineScope(Dispatchers.IO).launch {
            Log.d(TAG, "Push sending...")
            sendNotification("body push 1", "title push 1", "", 1)
            Log.d(TAG, "Push sent")
            jobFinished(params, false)
        }
    }

    override fun onStopJob(params: JobParameters?): Boolean {
        Log.d(TAG, "<Job interrupt>")
        return true
    }


    fun sendNotification(
        messageBody: String,
        messageTitle: String,
        largeIconPath: String,
        pushId: Int
    ) {

        val channelId = getString(R.string.consumer_notification_channel_id)
        val channelName = getString(R.string.consumer_notification_channel_name)
        val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.logo_anim1)
            .setColor(ContextCompat.getColor(this, R.color.colorAccent))
            .setColorized(true)
            .setContentTitle(messageTitle)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setLights(Color.YELLOW, 1000, 1000)
        

        val notificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // Since android Oreo notification channel is needed.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                channelId,
                channelName,
                NotificationManager.IMPORTANCE_DEFAULT
            )
            channel.enableLights(true)
            channel.lightColor = Color.YELLOW
            notificationManager.createNotificationChannel(channel)
        }

        notificationManager.notify(pushId, notificationBuilder.build())
    }


}

SettingsFragment.kt

private fun registerNotification() {
        //TODO("Not yet implemented")
        val componentService = ComponentName(requireContext(), MemoNotificationService::class.java)
        val info = JobInfo.Builder(MemoNotificationService.serviceId, componentService)
            .setPersisted(true) /*persist on boot*/ /*not sure if needed*/
            .setPeriodic(30 * 1000) /*once a day = 24 * 60 * 60 * 1000 */
            .build()
        val scheduler = requireContext().getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
        val resultCode = scheduler.schedule(info)
        if(resultCode == JobScheduler.RESULT_SUCCESS)
            Log.d(MemoNotificationService.TAG, "<Job scheduled>")
        else
            Log.d(MemoNotificationService.TAG, "<Job scheduling failed>")
    }

private fun unregisterNotification() {
        //TODO("Not yet implemented")
        val scheduler = requireContext().getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
        Log.d(MemoNotificationService.TAG, "<Job scheduling cancelling> :: ${scheduler.allPendingJobs}")
        scheduler.cancel(MemoNotificationService.serviceId)
        Log.d(MemoNotificationService.TAG, "<Job scheduling cancelled> :: ${scheduler.allPendingJobs}")
    }

AndroidManifest.xml

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<service

    android:name=".MemoNotificationService"
    android:permission="android.permission.BIND_JOB_SERVICE" />

Logcat

D/MemoPush: <Job scheduled>
D/MemoPush: <Job scheduling cancelling> :: [(job:4242/com.example.testjobservice/.MemoNotificationService)]
D/MemoPush: <Job scheduling cancelled> :: []

实际上我需要使用离线服务(整个应用程序中没有互联网)发送推送通知,例如每天一次,使用相同的通知,或者...... 这是实现这一目标的正确方法吗?

文档说最短调度程序时间是 15 分钟,所以这可能就是问题所在。 将代码更改为:

SettingsFragment.kt

private fun registerNotification() {
        val componentService = ComponentName(requireContext(), MemoNotificationService::class.java)
        val info = JobInfo.Builder(MemoNotificationService.serviceId, componentService) 
            .setPersisted(true)

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            //info.setPeriodic(24 * 60 * 60 * 1000,12 * 60 * 60 * 1000)
            info.setPeriodic(30 * 60 * 1000,15 * 60 * 1000) //for testing purpose
        }
        else {
            //info.setPeriodic(24 * 60 * 60 * 1000)
            info.setPeriodic(15 * 60 * 1000) //for testing purpose
        }

        val scheduler = requireContext().getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
        val resultCode = scheduler.schedule(info.build())
        if(resultCode == JobScheduler.RESULT_SUCCESS)
            Log.d(MemoNotificationService.TAG, "<Job scheduled>")
        else
            Log.d(MemoNotificationService.TAG, "<Job scheduling failed>")
}

我猜它很有魅力。

无论如何,对于进一步的解决方案,最好使用基于 AlarmManager (API < 21) 和 JobScheduler (API >= 21). 官方代码实验室:https://developer.android.com/codelabs/android-workmanager?index=..%2F..index#0