Android启动前台服务(startForegroundService)

问题:

APP in background in null uid
AndroidRuntime: android.app.RemoteServiceException: Context.startForegroundService()
 did not then call Service.startForeground():

注意事项:

  • 8.0适配:通知需要加上NotificationChannel,开启前台服务的方式startForegroundService()
  • 9.0适配:manifest.xml文件中需要增加权限:FOREGROUND_SERVICE

Android之 Service服务详解

1、前台权限:

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

2、Service中开启通知:

class LogUploadService : Service() {

    override fun onBind(arg0: Intent): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        Log.d("caowj", "LogUploadService onCreate")
        initNotification()
    }

    private fun initNotification() {
        val channelName = "埋点上传"
        val channelId = BuildConfig.APPLICATION_ID

		// 发送通知,把service置于前台
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        // 从Android 8.0开始,需要注册通知通道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH)
            notificationManager.createNotificationChannel(channel)
        }
        val notification = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.mipmap.app_icon)
            .setContentTitle("埋点Log上报")
            .setContentText("服务正在运行,请勿关闭")
            .setAutoCancel(false)
            .setOngoing(true)
            .build()
        // 注意第一个参数不能为0
        startForeground(1, notification)
    }

    override fun onDestroy() {
        //停止的时候销毁前台服务。
        stopForeground(true);
    }
}


3、启动Service:

// Android 8.0使用startForegroundService在前台启动新服务
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    startForegroundService(Intent(this, LogUploadService::class.java))
} else {
    startService(Intent(this, LogUploadService::class.java))
}

Android O对后台Service限制怎么解决

4、其他方案:

由于从Android 8.0开始禁止应用在后台运行时创建Service,所以要解决这种这种问题有以下几种方案:

  • 通过Context.startForegroundService()方式启动一个前台Service,前台Service的启动没有受到限制。
  • 集成Google Firebase Messaging。
  • 使用JobService;最小周期时长为 15 分钟
  • WorkManager: 周期性任务;最小周期时长为 15 分钟 (与 JobScheduler 相同)

官方建议使用JobScheduler 替换 后台Service。

从Android 8.0,使用JobScheduler替换后台Service,它会周期性启动一个任务,查询服务器,然后退出。相比于后台Service,它消耗的资源明显较少,间接提升了手机性能。

问题补充:

JobService 最小间隔时间要求大于15分钟;否则报错:

Requested interval +1m0s0ms for job 10 is too small; raising to +15m0s0ms   
Requested flex +1m0s0ms for job 10 is too small; raising to +5m0s0ms        

WorkManager: 周期性任务

5、JobScheduler实现定时间隔处理

Android之任务调度WorkManager和JobSchedule的使用

通过递归的方式,解决最小间隔时间要求大于15分钟的限制;

/**
 * JobScheduler实现定时间隔处理
 * 通过递归的方式,在onStartJob中,利用setMinimumLatency来设置时间间隔,执行完后再重新创建启用任务来实现
 */
class PeriodicJobService : JobService() {

    override fun onStartJob(p0: JobParameters?): Boolean {
        Log.i(TAG, "onStartJob---")
        startScheduler(this)
        return false
    }

    override fun onStopJob(p0: JobParameters?): Boolean = false

    companion object {
        var TAG: String = "caowj"
        var JOBID: Int = 100
        var InterValTime: Long = 10000
        private var jobScheduler: JobScheduler? = null
        private var jobInfo: JobInfo? = null

        fun startScheduler(context: Context) {
            jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
            cancelScheduler()
            if (jobInfo == null) {
                jobInfo = JobInfo.Builder(JOBID, ComponentName(context, PeriodicJobService::class.java))
                    .setMinimumLatency(InterValTime) // 最小为10秒
                    .build()
            }
            val result = jobScheduler?.schedule(jobInfo!!)
        }

        fun cancelScheduler() {
            jobScheduler?.cancel(JOBID)
        }
    }
}

需要提醒:

  • JobScheduler和WorkManager都只能在APP存活的时候执行,但是定时器是一直工作的。
  • 关闭APP再启动,JobScheduler并不能够直接继续运行,但是WorkManager可以。
  • 如果重启APP的时候,WorkManager任务的计时器应该已经执行了一次或多次,则会立即开始执行。
  • 重启App之后WorkManager如果直接执行了一个任务,则从这个时候开始算新的周期,不会按旧有周期走。

猜你喜欢

转载自blog.csdn.net/zhijiandedaima/article/details/131192337