背景中的定期任务

问题描述 投票:0回答:1

我目前正在构建一个通过向后端发送请求来启动会话的应用。之后,该应用程序必须每4.5分钟发送一次心跳请求。如果自上次成功请求后4.5分钟后,该应用程序未向后端发送请求,则该会话将被终止。心跳请求可以提前发送,这也意味着下一次心跳必须在该请求之后4.5分钟发送。用户开始会话后,他应该能够将应用程序置于后台以将设备用于其他用途。

我正在努力提出一种可以解决背景限制(打ze模式等)的解决方案。

我当前正在使用前台服务运行该应用程序。但是如果我不积极使用设备,则请求会在几分钟后停止。我尝试了WorkManager和AlarmManager。但是请求一直在延迟。

我玩过REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,这似乎可行,但我不想使用这种方法,因为Google似乎真的不喜欢使用此许可的应用程序。

我创建了一个测试应用程序,可以使用不同的方法。也许我做错了什么?

服务:

class MainService : Service() {

    private lateinit var wakeLock: PowerManager.WakeLock

    override fun onBind(intent: Intent?): IBinder? = null

    override fun onCreate() {
        super.onCreate()
        if (Build.VERSION.SDK_INT >= 26) {
            val appName = getString(R.string.app_name)
            val channelName = "$appName channel name"
            val channelImportance = NotificationManager.IMPORTANCE_HIGH
            val channelDescription = "$appName channel description"
            createNotificationChannel(this, NOTIFICATION_CHANNEL_ID, channelName, channelImportance, channelDescription)
        }
        val notification = createOngoingNotification(this, NOTIFICATION_REQUEST_CODE, R.mipmap.ic_launcher_round, "Content Text")
        startForeground(1000, notification)

        wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
            newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::MyWakelockTag").apply {
                acquire(1 * 60 * 60 * 1000L)
            }
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        intent?.action?.let {
            if (it == "Heartbeat") {
                val v = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    v.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE))
                }
            }
        }
        setNext()
        return START_STICKY
    }


    private fun setNext() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val intent = Intent(applicationContext, MainService::class.java)
            intent.action = "Heartbeat"
            val pendingIntent = PendingIntent.getService(applicationContext, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
            val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5 * 1000, pendingIntent)
        }
    }

    override fun onDestroy() {
        stopForeground(true)
        wakeLock.release()
        super.onDestroy()
    }

    companion object {

        const val REQUEST_CODE = 101
        const val NOTIFICATION_REQUEST_CODE = 100
        const val NOTIFICATION_CHANNEL_ID = "notification_channel_id"

        fun createOngoingNotification(context: Context, requestCode: Int, icon: Int, text: String): Notification {
            val contentIntent = Intent(context, MainActivity::class.java)
                .setAction(Intent.ACTION_MAIN)
                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
            val contentPendingIntent = PendingIntent.getActivity(context, requestCode, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT)
            return NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
                .setOngoing(true)
                .setSmallIcon(icon)
                .setContentTitle("Test Notification")
                .setContentText(text)
                .setContentIntent(contentPendingIntent)
                .build()
        }


        @RequiresApi(api = 26)
        fun createNotificationChannel(context: Context,
                                      id: String, name: String, importance: Int,
                                      description: String) {
            val channel = NotificationChannel(id, name, importance)
            channel.description = description
            val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }
    }
}
android android-service
1个回答
0
投票

我认为前台服务可能会停止,因为您在设置警报后未在其中执行任何操作。如果您正在使用前景服务,它将继续运行,因此,为了使其能够定期工作,我将放置一个可观察到的对象,例如每5秒发出一个值。您仅需要在4.5分钟后发出的一项,但这将使前台服务保持活动状态直到您需要它为止。使用rxjava:

Observable.intervalRange( 0 , 54, 0, 5, TimeUnit.SECONDS )
        .doOnNext{
          //You may not need this 
        }
        .doOnComplete {
            //heartbeat
            //start this observable again for other 4.5 minutes
        }

您将每5秒发出一个值54次。 54x5 = 270秒(4.5分钟)

© www.soinside.com 2019 - 2024. All rights reserved.