問(wèn)題:
APP in background in null uid
AndroidRuntime: android.app.RemoteServiceException: Context.startForegroundService()
did not then call Service.startForeground():
注意事項(xiàng):
- 8.0適配:通知需要加上NotificationChannel,開(kāi)啟前臺(tái)服務(wù)的方式startForegroundService()
- 9.0適配:manifest.xml文件中需要增加權(quán)限:FOREGROUND_SERVICE
Android之 Service服務(wù)詳解
1、前臺(tái)權(quán)限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
2、Service中開(kāi)啟通知:
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 = "埋點(diǎn)上傳"
val channelId = BuildConfig.APPLICATION_ID
// 發(fā)送通知,把service置于前臺(tái)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// 從Android 8.0開(kāi)始,需要注冊(cè)通知通道
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("埋點(diǎn)Log上報(bào)")
.setContentText("服務(wù)正在運(yùn)行,請(qǐng)勿關(guān)閉")
.setAutoCancel(false)
.setOngoing(true)
.build()
// 注意第一個(gè)參數(shù)不能為0
startForeground(1, notification)
}
override fun onDestroy() {
//停止的時(shí)候銷(xiāo)毀前臺(tái)服務(wù)。
stopForeground(true);
}
}
3、啟動(dòng)Service:
// Android 8.0使用startForegroundService在前臺(tái)啟動(dòng)新服務(wù)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(this, LogUploadService::class.java))
} else {
startService(Intent(this, LogUploadService::class.java))
}
Android O對(duì)后臺(tái)Service限制怎么解決
4、其他方案:
由于從Android 8.0開(kāi)始禁止應(yīng)用在后臺(tái)運(yùn)行時(shí)創(chuàng)建Service,所以要解決這種這種問(wèn)題有以下幾種方案:
- 通過(guò)Context.startForegroundService()方式啟動(dòng)一個(gè)前臺(tái)Service,前臺(tái)Service的啟動(dòng)沒(méi)有受到限制。
- 集成Google Firebase Messaging。
- 使用JobService;最小周期時(shí)長(zhǎng)為 15 分鐘
- WorkManager: 周期性任務(wù);最小周期時(shí)長(zhǎng)為 15 分鐘 (與 JobScheduler 相同)
官方建議使用JobScheduler 替換 后臺(tái)Service。
從Android 8.0,使用JobScheduler替換后臺(tái)Service,它會(huì)周期性啟動(dòng)一個(gè)任務(wù),查詢(xún)服務(wù)器,然后退出。相比于后臺(tái)Service,它消耗的資源明顯較少,間接提升了手機(jī)性能。
問(wèn)題補(bǔ)充:
JobService 最小間隔時(shí)間要求大于15分鐘;否則報(bào)錯(cuò):
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: 周期性任務(wù)
5、JobScheduler實(shí)現(xiàn)定時(shí)間隔處理
Android之任務(wù)調(diào)度WorkManager和JobSchedule的使用
通過(guò)遞歸的方式,解決最小間隔時(shí)間要求大于15分鐘的限制;文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-568583.html
/**
* JobScheduler實(shí)現(xiàn)定時(shí)間隔處理
* 通過(guò)遞歸的方式,在onStartJob中,利用setMinimumLatency來(lái)設(shè)置時(shí)間間隔,執(zhí)行完后再重新創(chuàng)建啟用任務(wù)來(lái)實(shí)現(xiàn)
*/
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)
}
}
}
需要提醒:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-568583.html
- JobScheduler和WorkManager都只能在APP存活的時(shí)候執(zhí)行,但是定時(shí)器是一直工作的。
- 關(guān)閉APP再啟動(dòng),JobScheduler并不能夠直接繼續(xù)運(yùn)行,但是WorkManager可以。
- 如果重啟APP的時(shí)候,WorkManager任務(wù)的計(jì)時(shí)器應(yīng)該已經(jīng)執(zhí)行了一次或多次,則會(huì)立即開(kāi)始執(zhí)行。
- 重啟App之后WorkManager如果直接執(zhí)行了一個(gè)任務(wù),則從這個(gè)時(shí)候開(kāi)始算新的周期,不會(huì)按舊有周期走。
到了這里,關(guān)于Android啟動(dòng)前臺(tái)服務(wù)(startForegroundService)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!