在一加手機(jī)上织堂,用戶升級(jí)了新版8.0的系統(tǒng)瓦灶,用戶將app切到后臺(tái),過(guò)一會(huì)兒就彈出“xxx app 已停止運(yùn)行”的彈窗贫导。
通過(guò)定位分析抛猫,發(fā)現(xiàn)下面?zhèn)z前置條件
- 8.0系統(tǒng)殺服務(wù)殺的很頻繁
- 為了保活孩灯,我們使用了倆Service互保的方式
馬上跑了26的模擬器闺金,果然復(fù)現(xiàn),日志如下:
main
Process: com.icourt.alpha.service.LocalService, PID: 4343
java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.icourt.alpha/.service.LocalService }: app is in background uid UidRecord{81da92c u0a91 SVC bg:+1m0s13ms idle procs:4 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1505)
at android.app.ContextImpl.startService(ContextImpl.java:1461)
at android.content.ContextWrapper.startService(ContextWrapper.java:644)
at com.icourt.alpha.service.RemoteService$RemoteServiceConnection.onServiceDisconnected(RemoteService.java:100)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1627)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1663)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
我查閱了android官網(wǎng)峰档,有如下一段描述:
Android 8.0 還對(duì)特定函數(shù)做出了以下變更:
- 如果針對(duì) Android 8.0 的應(yīng)用嘗試在不允許其創(chuàng)建后臺(tái)服務(wù)的情況下使用
startService()
函數(shù)败匹,則該函數(shù)將引發(fā)一個(gè)IllegalStateException
寨昙。- 新的
Context.startForegroundService()
函數(shù)將啟動(dòng)一個(gè)前臺(tái)服務(wù)。現(xiàn)在掀亩,即使應(yīng)用在后臺(tái)運(yùn)行舔哪,系統(tǒng)也允許其調(diào)用Context.startForegroundService()
。不過(guò)槽棍,應(yīng)用必須在創(chuàng)建服務(wù)后的五秒內(nèi)調(diào)用該服務(wù)的startForeground()
函數(shù)捉蚤。
解決方法就很簡(jiǎn)單了,把Service互啟的邏輯塊改為:
if (Build.VERSION.SDK_INT >= 26) {
context.startForegroundService(intent);
} else {
// Pre-O behavior.
context.startService(intent);
}
有個(gè)簡(jiǎn)寫(xiě):ContextCompat.startForegroundService(context, intent)
因?yàn)槲也幌胱層脩粼诳刂泼姘蹇吹酵ㄖ獧诹镀撸覜](méi)有在創(chuàng)建服務(wù)后的五秒內(nèi)調(diào)用startForeground()
缆巧。我馬上試了一下,果然沒(méi)有了“已停止運(yùn)行”豌拙,但是日志爆出了另一個(gè)ANR的錯(cuò)誤陕悬,雖然不是在主線程,也沒(méi)有彈窗按傅,但畢竟是個(gè)錯(cuò)誤墩莫,我想一探究竟。
回到官方的描述:在被啟動(dòng)的Service創(chuàng)建服務(wù)后的五秒內(nèi)調(diào)用startForground(0, new Notification())
逞敷,如果不調(diào)用或調(diào)用時(shí)間超過(guò)5秒會(huì)拋出一個(gè)ANR狂秦。
果不其然,我只有調(diào)用了推捐,這樣更好裂问,有前臺(tái)進(jìn)程,系統(tǒng)想殺都?xì)⒉坏袅恕?/p>
但仔細(xì)看一下官方文檔牛柒,你會(huì)發(fā)現(xiàn)堪簿,官方推薦使用JobScheduler
,這是api25的新特性皮壁。