You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加Android Jetpack Lifecycle Observer后出现内存泄漏,求解决思路

解决NavHostFragment关联已销毁Activity的内存泄漏问题

嘿,看你碰到了添加Lifecycle Observer后出现的内存泄漏问题,从LeakCanary给出的泄漏追踪信息来看,核心是已销毁的MainActivity被系统InputMethodManager相关链持有,最终导致NavHostFragment无法被GC回收。咱们一步步梳理解决思路:

LeakingInstance(referenceKey=3f842e15-cca3-465a-8345-3a241c8befca, referenceName=, instanceClassName=androidx.navigation.fragment.NavHostFragment, watchDurationMillis=561193, excludedLeak=false, leakTrace=
┬
├─ android.view.inputmethod.InputMethodManager$1
│ 是否泄漏:否(它是GC根节点)
│ com.android.internal.view.IInputMethodClient$Stub的匿名子类
│ ↓ InputMethodManager$1.this$0
│ ~~~~~~
├─ android.view.inputmethod.InputMethodManager
│ 是否泄漏:未知
│ ↓ InputMethodManager.mImeInsetsConsumer
│ ~~~~~~~~~~~~~~~~~~
├─ android.view.ImeInsetsSourceConsumer
│ 是否泄漏:未知
│ ↓ ImeInsetsSourceConsumer.mController
│ ~~~~~~~~~~~
├─ android.view.InsetsController
│ 是否泄漏:未知
│ ↓ InsetsController.mViewRoot
│ ~~~~~~~~~
├─ android.view.ViewRootImpl
│ 是否泄漏:未知
│ ↓ ViewRootImpl.mActivityConfigCallback
│ ~~~~~~~~~~~~~~~~~~~~~~~
├─ android.app.-$$Lambda$ActivityThread$ActivityClientRecord$HOrG1qglSjSUHSjKBn2rXtX0gGg
│ 是否泄漏:未知
│ ↓ -$$Lambda$ActivityThread$ActivityClientRecord$HOrG1qglSjSUHSjKBn2rXtX0gGg.f$0
│ ~~~
├─ android.app.ActivityThread$ActivityClientRecord
│ 是否泄漏:未知
│ ↓ ActivityThread$ActivityClientRecord.activity
│ ~~~~~~~~
├─ com.x.x.MainActivity
│ 是否泄漏:是(Activity#mDestroyed为true)
│ ↓ MainActivity.mFragments
├─ androidx.fragment.app.FragmentController
│ 是否泄漏:是(MainActivity↑存在泄漏)
│ ↓ FragmentController.mHost
├─ androidx.fragment.app.FragmentActivity$HostCallbacks
│ 是否泄漏:是(FragmentController↑存在泄漏)
│ ↓ FragmentActivity$HostCallbacks.mFragmentManager
├─ androidx.fragment.app.FragmentManagerImpl
│ 是否泄漏:是(FragmentActivity$HostCallbacks↑存在泄漏)
│ ↓ FragmentManagerImpl.mPrimaryNav
╰→ androidx.navigation.fragment.NavHostFragment ​
是否泄漏:是(Fragment#mFragmentManager为null) , retainedHeapSize=null)

先拆解泄漏核心逻辑

从追踪链能看出来:

  1. GC根是系统的InputMethodManager(本身不会泄漏),但它通过Insets相关的对象链,意外持有了已经标记为destroyed的MainActivity;
  2. MainActivity又关联着FragmentController、FragmentManager,最终导致本该被回收的NavHostFragment(它的mFragmentManager已经为null,说明FragmentManager已经尝试移除它)被强引用挂住,无法被GC回收。

具体解决思路

一、优先排查Lifecycle Observer的注册问题

这是你提到的新增Observer后出现的问题,大概率是Observer的引用方式出了问题:

  • 绑定正确的生命周期:如果Observer是服务于Fragment的,一定要用getViewLifecycleOwner().getLifecycle().addObserver(observer),而不是直接用Activity的Lifecycle,这样Observer会随Fragment视图生命周期自动解绑;
  • 手动移除Observer:如果是自定义的Observer,或者用了全局Lifecycle注册,一定要在组件的onDestroy(Fragment用onDestroyView)中调用lifecycle.removeObserver(observer);
  • 用弱引用持有组件:如果Observer必须访问Activity/Fragment,把强引用改成WeakReference,避免把组件死死挂住:
class MyObserver(private val activityRef: WeakReference<MainActivity>) : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun onResume() {
        activityRef.get()?.let { activity ->
            // 执行操作,用完就释放引用
        }
    }
}

二、清理NavHostFragment的关联引用

  • 移除导航回调:如果你给NavController加了OnDestinationChangedListener或者其他监听,记得在Activity的onDestroy中手动移除:
override fun onDestroy() {
    navController?.removeOnDestinationChangedListener(destinationListener)
    super.onDestroy()
}
  • 检查ViewModel引用:如果NavHostFragment关联的ViewModel持有了Activity/Fragment的强引用,要么改成弱引用,要么让ViewModel只持有Application上下文。

三、解决InputMethodManager的间接泄漏

这是系统层的常见场景,Activity销毁时软键盘未正确关闭可能导致这类引用残留:

  • 在MainActivity的onDestroy中手动隐藏软键盘:
override fun onDestroy() {
    val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
    currentFocus?.let { view ->
        imm.hideSoftInputFromWindow(view.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
    }
    super.onDestroy()
}
  • 检查Insets相关回调:如果你给View设置了OnApplyWindowInsetsListener,确保回调没有持有Activity的强引用,或者在销毁时移除监听。

四、验证泄漏是否修复

用LeakCanary重新运行测试,或者通过Android Studio的Memory Profiler:

  1. 触发Activity销毁流程;
  2. 手动触发GC(点击Profiler中的垃圾桶图标);
  3. 搜索NavHostFragment和MainActivity,看是否还有残留实例。

内容的提问来源于stack exchange,提问作者der_Fidelis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:43:15