ViewBinding内存泄露

作者: 杨0612 | 来源:发表于2021-12-15 17:06 被阅读0次
在Fragment中使用ViewBinding出现内存泄露。

场景:在MainActivity中分别加载两个Fragment处理业务。
通过以下方式加载AFragment:

       supportFragmentManager.commit {
            add(R.id.contentLayout, FirstFragment())
            addToBackStack(null)
        }

在AFragment中触发耗时任务加载数据;

class AFragment : Fragment() {

    private var _binding: FragmentFirstBinding? = null
    private val binding get() = _binding!!

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            val date = withContext(Dispatchers.IO) {
                delay(10000 )//模拟耗时加载数据
                "success"
            }
            binding.buttonFirst.text = date
        }
    }

在耗时任务还没有结束时,用户触发加载BFragment;
加载方式如下:

        supportFragmentManager.commit {
            replace(R.id.contentLayout, SecondFragment())
            addToBackStack(null)
        }

大家可能有注意到了,两个Fragment都会加到回退栈,这是为了在触发回退键时可以回到上一个组件,当然,实现方式有很多,我们不做过多的讨论。

这时候通过LeakCanary可以发现有内存泄露 20211215162636.jpg
1处是AFragment的ViewBinding实例,2处是AFragment布局id,3处是布局的类型。在3处,提示有内存泄露,也就是view出现了泄露。在4处,LeakCanary给了建议:对view的引用应该要被clear避免出现泄露。
引用链:Fragment-ViewBinding-根布局
为什么会出现泄露呢?

从AFragment到BFragment,前者生命周期从onPause->onStop->onDestoryView,注意这里只走到onDestoryView,并没有onDetach以及onDestory(不要问我为什么,这是Framework决定的)。其实也很好理解,AFragment是加入了回退栈,也就是期望被恢复,为了不占用过多的内存,Framework这时候会把view销毁,注意不是销毁Fragment,但view被Fragment持有,所以就出现了内存泄露。
可以简单把ViewBinding理解为对所有view封装,方便外部调用。
以下是onDestoryView官方注释,注意到这句“The next time the fragment needs
* to be displayed, a new view will be created”,当Fragment恢复时,会创建新的view添加到Fragment,也就是重走onCreateView,那么我理解旧的view就应该可以被销毁。


    /**
     * Called when the view previously created by {@link #onCreateView} has
     * been detached from the fragment.  The next time the fragment needs
     * to be displayed, a new view will be created.  This is called
     * after {@link #onStop()} and before {@link #onDestroy()}.  It is called
     * <em>regardless</em> of whether {@link #onCreateView} returned a
     * non-null view.  Internally it is called after the view's state has
     * been saved but before it has been removed from its parent.
     */
    @MainThread
    @CallSuper
    public void onDestroyView() {
        mCalled = true;
    }
解决方案

将ViewBinding置空就欧了。其实这也是官方的建议,当你新建项目的时候,就能看到这样的案列。

   override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

#######总结
当出现Fragment没有被销毁,而view需要被销毁时,要注意把ViewBinding置空,以免出现内存泄露。

以上分析有不对的地方,请指出,互相学习,谢谢哦!

相关文章

  • ViewBinding内存泄露

    在Fragment中使用ViewBinding出现内存泄露。 场景:在MainActivity中分别加载两个Fra...

  • 内存泄露系列文章(一) - 内存泄露原因及影响

    前言 内存泄露系列文章内存泄露系列文章(一) - 内存泄露原因及影响内存泄露系列文章(二) - 内存泄露监测及分析...

  • 内存泄露系列文章(三) - 内存泄露解决方案

    前言 内存泄露系列文章内存泄露系列文章(一) - 内存泄露原因及影响内存泄露系列文章(二) - 内存泄露监测及分析...

  • 内存溢出与内存泄露

    目录 [TOC] 1 内存泄露与内存溢出的区别 1.1 内存泄露 内存泄露(Memory Leak),指的是堆内存...

  • 内存泄漏详细分析

    首先,什么是内存泄露?经常听人谈起内存泄露,但要问什么是内存泄露,没几个说得清楚。内存泄露是指无用对象(不再使用的...

  • Java弱引用学习 WeakHashMap、ReferenceQ

    上一篇文章 Java内存泄露学习 ThreadLocal真的会内存泄露吗 提到ThreadLocal内存泄露的问题...

  • 内存优化

    内存优化主要是分析内存泄露和内存溢出。将从内存是怎么分配,内存怎么出现泄露和溢出,用工具判断什么情况出现泄露,找出...

  • 内存优化

    内存泄露的原因 四种引用类型 常见的内存泄露 1.内部类导致内存泄露 Handler 2.Context导致内存泄...

  • 内存泄漏/管理

    ARC 下内存泄露的那些点performSelector延时调用导致的内存泄露iOS ARC下几种导致内存泄露的场...

  • 源码分析:LeakCanary 如何实现内存泄露监测

    LeakCanary 是一个非常强大的内存泄露监测工具,可以实现打印内存泄露的信息。Android 的内存泄露检测...

网友评论

    本文标题:ViewBinding内存泄露

    本文链接:https://www.haomeiwen.com/subject/uohyfrtx.html