问题描述
刚开始与Leak Canary一起了解内存泄漏,因此请谅解或误解任何内容。 泄漏金丝雀告诉我内存泄漏,我将其缩小到这一行
NavigationUI.setupActionBarWithNavController(
it,navController
)
导航控制器被调用并设置为这样的变量
val navController = findNavController(this@PokemonDetailFragment)
“ it”是我的活动投射到应用兼容活动,完整的代码段如下所示:
mainActivity = (activity as AppCompatActivity)
mainActivity?.let {
it.setSupportActionBar(toolbar)
val navController = findNavController(this@PokemonDetailFragment)
NavigationUI.setupActionBarWithNavController(
it,navController
)
}
我已经尝试了三件事:1.注入活动,2.将活动设置为全局可为空的变量,并在onDestroyView中将其设置为null,并且3.尝试使用NavigationUI.setupWithNavController而不是使用setActionBarWithNavController的方法。工具栏和导航控制器
NavigationUI.setupWithNavController(
binding.toolbar,findNavController(this@PokemonDetailFragment)
)
但这些都不能解决问题。
删除第一个代码块肯定可以消除泄漏,但是Leak Canary并没有将泄漏显示为第三方库,并且确实说这是我的代码下面的变量是堆转储
```
┬───
│ GC Root: Local variable in native code
│
├─ android.os.HandlerThread instance
│ Leaking: NO (PathClassLoader↓ is not leaking)
│ Thread name: 'LeakCanary-Heap-Dump'
│ ↓ HandlerThread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│ Leaking: NO (InternalLeakCanary↓ is not leaking and A ClassLoader is never leaking)
│ ↓ PathClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│ Leaking: NO (InternalLeakCanary↓ is not leaking)
│ ↓ Object[].[502]
├─ leakcanary.internal.InternalLeakCanary class
│ Leaking: NO (MainActivity↓ is not leaking and a class is never leaking)
│ ↓ static InternalLeakCanary.resumedActivity
├─ com.sealstudios.pokemonApp.MainActivity instance
│ Leaking: NO (FragmentContainerView↓ is not leaking and Activity#mDestroyed is false)
│ ↓ MainActivity._binding
├─ com.sealstudios.pokemonApp.databinding.ActivityMainBinding instance
│ Leaking: NO (FragmentContainerView↓ is not leaking)
│ ↓ ActivityMainBinding.navHostFragment
├─ androidx.fragment.app.FragmentContainerView instance
│ Leaking: NO (View attached)
│ mContext instance of com.sealstudios.pokemonApp.MainActivity with mDestroyed = false
│ View.parent androidx.constraintlayout.widget.ConstraintLayout attached as well
│ View#mParent is set
│ View#mAttachInfo is not null (view attached)
│ View.mID = R.id.nav_host_fragment
│ View.mWindowAttachCount = 1
│ ↓ FragmentContainerView.mKeyedTags
│ ~~~~~~~~~~
├─ android.util.SparseArray instance
│ Leaking: UNKNowN
│ ↓ SparseArray.mValues
│ ~~~~~~~
├─ java.lang.Object[] array
│ Leaking: UNKNowN
│ ↓ Object[].[0]
│ ~~~
├─ androidx.navigation.NavHostController instance
│ Leaking: UNKNowN
│ ↓ NavHostController.mOnDestinationChangedListeners
│ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
├─ java.util.concurrent.copyOnWriteArrayList instance
│ Leaking: UNKNowN
│ ↓ copyOnWriteArrayList.array
│ ~~~~~
├─ java.lang.Object[] array
│ Leaking: UNKNowN
│ ↓ Object[].[1]
│ ~~~
├─ androidx.navigation.ui.ActionBarOnDestinationChangedListener instance
│ Leaking: UNKNowN
│ ↓ ActionBarOnDestinationChangedListener.mContext
│ ~~~~~~~~
├─ android.view.ContextThemeWrapper instance
│ Leaking: UNKNowN
│ ContextThemeWrapper wraps an Activity with Activity.mDestroyed false
│ ↓ ContextThemeWrapper.mBase
│ ~~~~~
├─ dagger.hilt.android.internal.managers.ViewComponentManager$FragmentContextwrapper instance
│ Leaking: UNKNowN
│ ViewComponentManager$FragmentContextwrapper wraps an Activity with Activity.mDestroyed false
│ ↓ ViewComponentManager$FragmentContextwrapper.fragment
│ ~~~~~~~~
╰→ com.sealstudios.pokemonApp.ui.PokemonDetailFragment instance
Leaking: YES (ObjectWatcher was watching this because com.sealstudios.pokemonApp.ui.PokemonDetailFragment received Fragment#onDestroy() callback and Fragment#mFragmentManager is null)
key = 724affdf-d1ac-47ff-82b8-6907ced5b666
watchDurationMillis = 9052
retainedDurationMillis = 4051
MetaDATA
Build.VERSION.SDK_INT: 29
Build.MANUFACTURER: Google
LeakCanary version: 2.4
App process name: com.sealstudios.pokemonApp
Analysis duration: 14474 ms```
感谢任何帮助,我只想设置需要AppCompatActivity的工具栏,然后正确处理它或允许系统执行此操作
我正在使用Hilt,尽管我的堆中确实提到了ContextThemeWrapper-https://github.com/google/dagger/issues/2070
,但我不确定这是否相关。解决方法
对此一无所知,手动进行设置可以消除内存泄漏
@SuppressLint("DefaultLocale")
private fun setActionBar() {
binding.toolbar.outlineProvider = null
binding.appBarLayout.outlineProvider = null
(activity as AppCompatActivity).setSupportActionBar(binding.toolbar)
(activity as AppCompatActivity).supportActionBar.apply {
this?.setHomeButtonEnabled(true)
this?.setDisplayHomeAsUpEnabled(true)
}
}
,
我认为问题出在 NavigationUI.setupWithNavController()
函数上。
让我们看看下面的代码片段:
public static void setupWithNavController(@NonNull Toolbar toolbar,@NonNull final NavController navController,@NonNull final AppBarConfiguration configuration) {
navController.addOnDestinationChangedListener(
new ToolbarOnDestinationChangedListener(toolbar,configuration));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
navigateUp(navController,configuration);
}
});
}
如我们所见,您正在向 navController
添加一个侦听器,它是 ToolbarOnDestinationChangedListener()
的一个新实例。
因为当 Activity/Fragment 生命周期进入 Destroy 状态时你没有移除 navController 的监听器,这很可能是你的问题所在。
,我强烈建议在 onDestroy()
中取消设置(归零)片段中每个使用过的对象,尤其是位图:
@Override
public void onDestroy() {
super.onDestroy();
// Here is my example:
myBigBitmap = null;
adapter = new MyAdapter(requireContext(),new String[0],new Bitmap[0]);
listView.setAdapter(adapter);
}
这是唯一正确的方法。工作 100%。