原理通過注冊activity和fragment的callback監(jiān)聽來觀察當前頁面是否destroy
Application中
監(jiān)聽activity 調用 registerActivityLifecycleCallbacks(this)
監(jiān)聽Fragment如下 :
// 注冊 Activity 生命周期監(jiān)聽器仪或,以監(jiān)聽每個 Activity 的 Fragment 生命周期
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
if (activity is FragmentActivity) {
// 對于 FragmentActivity材泄,注冊 Fragment 生命周期回調
activity.supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentCreated(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
Log.d("FragmentLifecycle", "Fragment ${f.javaClass.simpleName} onCreated in ${activity.javaClass.simpleName}")
}
override fun onFragmentStarted(fm: FragmentManager, f: Fragment) {
Log.d("FragmentLifecycle", "Fragment ${f.javaClass.simpleName} onStarted in ${activity.javaClass.simpleName}")
}
override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
Log.d("FragmentLifecycle", "Fragment ${f.javaClass.simpleName} onResumed in ${activity.javaClass.simpleName}")
}
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
Log.d("FragmentLifecycle", "Fragment ${f.javaClass.simpleName} onPaused in ${activity.javaClass.simpleName}")
}
override fun onFragmentStopped(fm: FragmentManager, f: Fragment) {
Log.d("FragmentLifecycle", "Fragment ${f.javaClass.simpleName} onStopped in ${activity.javaClass.simpleName}")
}
override fun onFragmentDestroyed(fm: FragmentManager, f: Fragment) {
Log.d("FragmentLifecycle", "Fragment ${f.javaClass.simpleName} onDestroyed in ${activity.javaClass.simpleName}")
}
}, true)
}
}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
})
當任意一個 Fragment 被創(chuàng)建、啟動、恢復诸典、暫停、停止或銷毀時,都會通過 FragmentLifecycleCallbacks 打印日志咙边。
通過這種方式,你可以在全局范圍內監(jiān)聽每個 Activity 中的 Fragment 的生命周期次员。
在onDestroy方法中檢測到對象的弱引用還有沒有值败许,有值說明沒有被回收存在內存泄漏,沒有值說明已經被回收了淑蔚,當前對象不存在泄漏
存在問題:
-
性能開銷(只能檢測debug環(huán)境 線上會很卡頓(線上檢測方式可以用KOOM類庫快手開源的))
內存和CPU負擔:LeakCanary 在進行內存快照(Heap Dump)和分析時會消耗額外的內存和CPU資源市殷。對于較大的應用或復雜的場景,生成和分析堆內存快照可能會導致明顯的性能下降刹衫,尤其是在低性能設備上醋寝。
內存使用增加:LeakCanary 本身會消耗一定的內存來跟蹤對象,并且 Heap Dump 文件會占用設備存儲空間带迟,這可能導致在調試環(huán)境中內存壓力增大音羞。
誤報問題
假陽性(False Positive):由于 LeakCanary 基于弱引用和GC回收機制來判斷對象是否被泄漏,在某些情況下邮旷,系統(tǒng)可能延遲回收對象或者強制回收未及時發(fā)生黄选,導致 LeakCanary 誤報內存泄漏。
復雜場景的誤報:對于某些復雜的引用關系(如系統(tǒng)級別的引用或長期存在的靜態(tài)引用)婶肩,LeakCanary 可能無法準確判斷是否為實際內存泄漏办陷,尤其是在多線程或異步操作較多的情況下。嵌套的fragment會被漏掉檢查
比如app首頁有三個tab(fragment) 在tab1中 嵌套了一個viewpager律歼,viewpager中又有很多fragment民镜,LeakCanary源碼中原理是通過activity的fragmentManager中監(jiān)聽第一層的fragment,無法監(jiān)聽到第二層第三層的所以會導致漏掉檢查险毁。
4 activity也會存在此問題
LeakCanary觀察的是能夠執(zhí)行到onDestroy生命周期的類制圈,如果觀察不到那就會漏掉,申請情況下會觀察不到呢 以下舉例說明:
activity A啟動activity B
在 Android 中畔况,當 ActivityA 啟動 ActivityB 時鲸鹦,ActivityA 的生命周期會隨著 ActivityB 的啟動過程發(fā)生變化。具體來說:
ActivityB 的啟動:當 ActivityB 被啟動時跷跪,它的生命周期依次執(zhí)行 onCreate()馋嗜、onStart() 和 onResume()。
ActivityA 的 onStop():當 ActivityB 完成 onResume()吵瞻,也就是 ActivityB 顯示在前臺并獲得焦點時葛菇,此時 ActivityA 會進入后臺甘磨,然后 ActivityA 的 onStop() 方法被調用。
源碼分析:為什么ActivityB 完成 onResume()后才執(zhí)行ActivityA 的 onStop()
因為AMS的管理機制眯停,當 ActivityB 執(zhí)行onResume()的時候 消息隊列中會add一個idlehandler 告訴Activity主線程空閑了济舆,然后會通知ams ams收到這個消息后會通知ActivityA該執(zhí)行onStop了.
如果在執(zhí)行ActivityB onResume()的時候一直在刷新UI 比如動畫此時Activity主線程沒有空閑,所以就不會執(zhí)行idlehandler ams就不會通知ActivityA 執(zhí)行 onStop() 所以就會導致ActivityA無法被回收莺债。 當 ActivityB 執(zhí)行onResume()的時候 AMS會設置一個定時機制10s后會通知ActivityA 執(zhí)行onStop方法
(補充和詳細分析:
- AMS 與消息隊列的調度機制
當 ActivityB 執(zhí)行到 onResume() 時滋觉,它會獲取焦點并進入前臺。此時九府,AMS 會將一個 IdleHandler 添加到 ActivityThread 的消息隊列中,這個 IdleHandler 負責通知 AMS ActivityB 進入前臺且 ActivityA 已經不再處于活躍狀態(tài)煌妈,因此可以讓 ActivityA 執(zhí)行 onStop()璧诵。
這里的關鍵點是:消息隊列的空閑狀態(tài)之宿。如果 ActivityB 在 onResume() 階段執(zhí)行耗時任務(例如動畫色难、UI 刷新等)枷莉,消息隊列可能不會很快進入空閑狀態(tài),導致 IdleHandler 沒有機會執(zhí)行蹲盘,從而延遲 ActivityA 的 onStop()召衔。
AMS 定時機制
AMS 確實會設置一個超時機制(通常是 10 秒左右)严蓖,以確保 ActivityA 能及時執(zhí)行 onStop()。這個定時機制是為了防止某些情況下 ActivityThread 長時間無法進入空閑狀態(tài)吩坝,導致 onStop() 被過度延遲钉寝。如果超時后還沒有進入空閑狀態(tài),AMS 會強制要求 ActivityA 執(zhí)行 onStop() 以避免資源浪費逮走。進一步分析和建議
UI 線程占用問題:如果 ActivityB 在 onResume() 期間執(zhí)行了大量的 UI 刷新操作或者動畫,使得主線程忙碌而無法空閑,確實會延遲 IdleHandler 的執(zhí)行窿锉。為了解決這種情況嗡载,可以考慮將耗時操作(如動畫或復雜 UI 刷新)放在合適的地方進行鼻疮,比如在 onPostResume()、onWindowFocusChanged() 或者通過 Handler 延遲執(zhí)行琳轿,這樣可以確保主線程有足夠的時間空閑,從而讓 IdleHandler 觸發(fā) onStop()崭篡。
定時機制的作用:AMS 的定時機制是作為安全網的一部分,用來保證生命周期的正確性琉闪。然而,依賴定時機制并不是最佳實踐,因為這可能會導致性能問題或內存泄漏斯入。應盡量避免阻塞 onResume() 的主線程操作砂碉。
總的來說刻两,你的理解是正確的,但需要注意的是滋迈,延遲 onStop() 并不是常態(tài)帝美,應該盡量優(yōu)化 Activity 的啟動和 UI 刷新操作硕旗,避免占用主線程資源過多導致生命周期回調被阻塞。)