使用 app 程序中,禁用權限后,app 所有行程被殺,俺是第一次碰到,,,
源于測驗提的一個bug:
直播程序中,設定-禁用相機權限后,再打開 app 直播崩潰,
Bug 復現
通過復現,確實是這樣,不過崩潰的是 NPE 或別的,跟相機權限一點關系都沒有,
連上手機開始除錯吧,看看日志啥啥的,
打開 app 開播,去系統設定把 app 的相機權限從允許改為禁止,
Logcat 的日志沒了,并且 app 的所有行程都被殺了,一個也沒留,
從最近任務串列或桌面 Icon 點擊 app,白屏了一小會兒,然后崩了,
行程新建,然后重建堆疊頂的 activity,然而如果程式讀取在記憶體中存的物件時,發生了 npe 造成崩潰,
這,,,
試試微信去,
我驚了,微信它重啟了,重新走冷啟動流程,
為啥 app 行程會被干掉
可以看看 Android marshmallow dynamic permission change kills all application processes
在線考古!
既然這是 Android 系統的機制,那我們想想辦法在這種情況下,怎么能讓 app 不崩潰吧,
解決方法
onCreate 中判斷 bundle != null
很多人考慮在基類的 onCreate 方法中判斷 bundle 是否為 null,來判定 activity 被重建,
這個做法的依據是,權限禁止后,再打開 app,堆疊頂的 activity 的 onCreate 方法的 bundle 不為 null,存了一些系統自動傳入的 bundle,
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
val intent = Intent(this, LaunchActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
overridePendingTransition(0, 0)
finish()
}
}
但是如果在程式有需求存 bundle 時,這個方法是不是就不適用了呢 ~
通過 ActivityLifecycleCallbacks
另外發現的一種方法:
在Application 定義一個Boolean型別的屬性,isKilled = true 默認為true, 注冊 ActivityLifecycleCallbacks 回呼,在onActivityCreated 方法,先判斷activity 是否是Launch ,若是則將Application.isKilled 賦值為false,若不是Launch 判斷 Application.isKilled 是否為true, 若是true 說明 Application 被重建了,這時候跳轉到Launch并殺掉剛重建的Activity
# 應用壓到后臺,關閉應用某個權限后,應用無法正常使用
具體實作:
自定義 PreventProcessKill 類,并實作 Application.ActivityLifecycleCallbacks 介面
class PreventProcessKill: Application.ActivityLifecycleCallbacks {
companion object {
const val TAG = "PreventProcessKill"
}
private var activityCount = 0
override fun onActivityCreated(activity: Activity?, bundle: Bundle?) {
Logs.e(TAG, "onActivityCreated activity=($activity) bundle=($bundle)")
if (activity != null && activity is LaunchActivity) {
if (activityCount == 0 || activity.isTaskRoot()) {
Logs.e(TAG, "onActivityCreated set isKilled false ")
MyApplication.isKilled = false
}
}
if (MyApplication.isKilled) {
Logs.e(TAG, "onActivityCreated isKilled == true, start restartApp")
// 行程被殺死,重啟app
restartApp(activity);
return;
}
}
override fun onActivityStarted(activity: Activity?) {
Logs.e(TAG, "onActivityStarted activity=$activity")
activityCount++
}
override fun onActivityResumed(activity: Activity?) {
Logs.e(TAG, "onActivityResumed activity=$activity")
}
override fun onActivityPaused(activity: Activity?) {
Logs.e(TAG, "onActivityPaused activity=$activity")
}
override fun onActivityStopped(activity: Activity?) {
Logs.e(TAG, "onActivityStopped activity=$activity")
activityCount--
}
override fun onActivitySaveInstanceState(activity: Activity?, bundle: Bundle?) {
Logs.e(TAG, "onActivitySaveInstanceState activity=($activity) bundle=($bundle)")
}
override fun onActivityDestroyed(activity: Activity?) {
Logs.e(TAG, "onActivityDestroyed activity=$activity")
}
/**
* 走啟動流程
*/
private fun restartApp(activity: Activity?) {
val intent = Intent(activity, LaunchActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
activity?.startActivity(intent)
activity?.overridePendingTransition(0, 0)
activity?.finish()
}
}
在 Application 中定義 默認為 true 的 isKilled 屬性,
public class MyApplication extends MultiDexApplication {
public boolean isKilled = true;
}
文末
第二個方法我認為比在 onCreate 中判斷 bundle 是否為空的方法要好一些,
這兩個方法都存在一個問題,就是打開 app 時,會白屏一小會兒,
微信沒有白屏,好想問問微信的人是咋處理的,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/290299.html
標籤:其他
