问题:
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分钟的限制;文章来源:https://www.toymoban.com/news/detail-568583.html
/**
* 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)
}
}
}
需要提醒:文章来源地址https://www.toymoban.com/news/detail-568583.html
- JobScheduler和WorkManager都只能在APP存活的时候执行,但是定时器是一直工作的。
- 关闭APP再启动,JobScheduler并不能够直接继续运行,但是WorkManager可以。
- 如果重启APP的时候,WorkManager任务的计时器应该已经执行了一次或多次,则会立即开始执行。
- 重启App之后WorkManager如果直接执行了一个任务,则从这个时候开始算新的周期,不会按旧有周期走。
到了这里,关于Android启动前台服务(startForegroundService)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!