Android DataBinding 正在泄漏内存

Var*_*Raj 18 android kotlin android-databinding

我正在使用数据绑定,我已经lateinit var为绑定声明了一个,当我要去不同的片段时,Leaky canary 显示了一个泄漏。

分段

class HomeFragment : BottomNavViewHostBaseFragment() {

    private lateinit var viewModel: HomeViewModel
    private lateinit var binding: FragmentHomeBinding

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        viewModel = ViewModelProviders.of(this).get(HomeViewModel::class.java)
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
        binding.lifecycleOwner = viewLifecycleOwner
        binding.viewModel = viewModel
        return binding.root
    }

   ...
}
Run Code Online (Sandbox Code Playgroud)

这是来自 Leaky Carny 的信息

androidx.constraintlayout.widget.ConstraintLayout has leaked:
Toast$TN.mNextView
? LinearLayout.mContext
? MainActivity.navigationView
? NavigationView.listener
? BaseFragment$setNavigationDrawerItemSelectedListener$1.this$0 (anonymous implementation of com.google.android.material.navigation.NavigationView$OnNavigationItemSelectedListener) ? OrdersHostFragment.mFragmentManager
? FragmentManagerImpl.mActive
? HashMap.table
? array HashMap$HashMapEntry[].[0]
? HashMap$HashMapEntry.value
? HomeFragment.!(binding)!
? FragmentHomeBindingImpl.!(mboundView0)!
? ConstraintLayout
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题,我是否需要在binding=null里面做onDestroyView?但如果我需要这样做,那有什么意义binding.lifecycleOwner = viewLifecycleOwner呢?

ere*_*130 20

这是谷歌文档中推荐的初始化和清除 Fragments 绑定的方法:

科特林:

private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}
Run Code Online (Sandbox Code Playgroud)

爪哇:

private ResultProfileBinding binding;

@Override
public View onCreateView (LayoutInflater inflater, 
                          ViewGroup container, 
                          Bundle savedInstanceState) {
    binding = ResultProfileBinding.inflate(inflater, container, false);
    View view = binding.getRoot();
    return view;
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null;
}
Run Code Online (Sandbox Code Playgroud)

此外,这里有一篇中等的博客文章,可以阅读以消除与 Property Delegate 的绑定内存泄漏。

  • 请注意,该链接指的是 ViewBinding,但我认为该概念与 DataBinding 相同,即使我找不到这么说的文档,并且示例也不会取消视图引用。 (2认同)

Con*_*Var 6

根据片段生命周期onDestroyView()被调用,但片段没有完全销毁 - 所以onDestroy()没有被调用。在这种情况下,如果您不手动重置绑定属性,它会引用视图树(这是某种泄漏)。

但如果我需要这样做,那么 binding.lifecycleOwner = viewLifecycleOwner 的意义何在?

如果您提供LifecycleOwner绑定对象,它允许观察LiveData生成的绑定类内的所有对象。但它无法了解外部binding实例的外部引用(来自项目的任何其他类) - 这就是它无法自动重置它们的原因。

  • @MohsenEinhesari,如果您将绑定保存在片段中的某个变量中,则手动将其清空是绝对正常的(因为您需要为变量中存储的每个视图执行此操作),因为片段的**视图**的生命周期小于片段的生命周期。 (3认同)
  • @MohsenEinhesari,变量中的存储绑定并不总是需要的 - 所以它取决于屏幕的逻辑。根据文档,[`unbind()`](https://developer.android.com/reference/android/databinding/ViewDataBinding.html#unbind()) 只是删除侦听器,但仍然缓存视图。 (2认同)