Navigation+ViewPage2+FragmentStateAdapter=内存泄漏?

关键点

FragmentStateAdapter是继承自RecyclerView.AdapterViewPage2是基于RecyclerView进行实现的。FragmentStateAdapter在实例化的时候,会持有一个Lifecycle对象,而该Lifecycle对象从Fragment或者Activity得来。

源码解析

FragmentStateAdapter{

    ...

    //该方法是RecyclerView.Adapter的回调,在RecyclerView调用setAdapter时进入

    @CallSuper

    @Override

    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {

        checkArgument(mFragmentMaxLifecycleEnforcer == null);

        mFragmentMaxLifecycleEnforcer = new FragmentMaxLifecycleEnforcer();

        mFragmentMaxLifecycleEnforcer.register(recyclerView);

    }

    //该方法是RecyclerView.Adapter的回调,在RecyclerView首次调用setAdapter时不进入,之后每次调用setAdapter都进入

    @CallSuper

    @Override

    public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {

        mFragmentMaxLifecycleEnforcer.unregister(recyclerView);

        mFragmentMaxLifecycleEnforcer = null;

    }

    //内部类

    class FragmentMaxLifecycleEnforcer {

        private ViewPager2.OnPageChangeCallback mPageChangeCallback;

        private RecyclerView.AdapterDataObserver mDataObserver;

        private LifecycleEventObserver mLifecycleObserver;

        private ViewPager2 mViewPager;

        private long mPrimaryItemId = NO_ID;

        void register(@NonNull RecyclerView recyclerView) {

            //利用传入的recyclerView,取recyclerView.getParent()来获得ViewPage2

            mViewPager = inferViewPager(recyclerView);

            mPageChangeCallback = new ViewPager2.OnPageChangeCallback() {

                @Override

                public void onPageScrollStateChanged(int state) {

                    updateFragmentMaxLifecycle(false);

                }

                @Override

                public void onPageSelected(int position) {

                    updateFragmentMaxLifecycle(false);

                }

            };

            mViewPager.registerOnPageChangeCallback(mPageChangeCallback);

            mDataObserver = new DataSetChangeObserver() {

                @Override

                public void onChanged() {

                    updateFragmentMaxLifecycle(true);

                }

            };

            registerAdapterDataObserver(mDataObserver);

            mLifecycleObserver = new LifecycleEventObserver() {

                @Override

                public void onStateChanged(@NonNull LifecycleOwner source,

                        @NonNull Lifecycle.Event event) {

                    //接口的实现,造成内存泄漏的关键点,这里持有外部对象mViewPager的引用

                    updateFragmentMaxLifecycle(false);

                }

            };

            //造成内存泄漏的关键点,这里把属于Fragment的Lifecycle对象,注册了一个LifecycleEventObserver对象

            mLifecycle.addObserver(mLifecycleObserver);

        }

        void unregister(@NonNull RecyclerView recyclerView) {

            ViewPager2 viewPager = inferViewPager(recyclerView);

            viewPager.unregisterOnPageChangeCallback(mPageChangeCallback);

            unregisterAdapterDataObserver(mDataObserver);

            //释放掉内存泄漏的关键点,因为该方法只有第二次setAdapter才会进入,所以在销毁的时候需要调用setAdapter(null)

            mLifecycle.removeObserver(mLifecycleObserver);

            mViewPager = null;

        }

    }

}

 

RecyclerView{

    public void setAdapter(@Nullable Adapter adapter) {

        // bail out if layout is frozen

        setLayoutFrozen(false);

        //这里调用了下面的setAdapterInternal方法

        setAdapterInternal(adapter, false, true);

        processDataSetCompletelyChanged(false);

        requestLayout();

    }

    private void setAdapterInternal(@Nullable Adapter adapter, boolean compatibleWithPrevious,

            boolean removeAndRecycleViews) {

        //第一次进入时mAdapter为null

        if (mAdapter != null) {

            //第二次之后mAdapter不为null

            mAdapter.unregisterAdapterDataObserver(mObserver);

            mAdapter.onDetachedFromRecyclerView(this);

        }

        if (!compatibleWithPrevious || removeAndRecycleViews) {

            removeAndRecycleViews();

        }

        mAdapterHelper.reset();

        final Adapter oldAdapter = mAdapter;

        mAdapter = adapter;

        if (adapter != null) {

            adapter.registerAdapterDataObserver(mObserver);

            adapter.onAttachedToRecyclerView(this);

        }

        if (mLayout != null) {

            mLayout.onAdapterChanged(oldAdapter, mAdapter);

        }

        mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);

        mState.mStructureChanged = true;

    }

}

 

场景分析

  • 场景

因为Navigation的设计机制,Fragment是利用replace跳转的,在跳转页面时会调用onDestroyView(),而该方法调用后,在onCreateView()函数里所创建的View需要销毁。

  • 造成内存泄漏的原因

因为FragmentStateAdapter会持有FragmentLifecycle对象,并且在recyclerView.setAdapter时会注册LifecycleEventObserver,而LifecycleEventObserver对象的实现持有了外部类的ViewPager2引用,在Lifecycle对象没释放掉LifecycleEventObserver对象时,就代表着FragmentLifecycle引用了ViewPager2对象,从而导致onDestroyView()函数执行时,没办法释放掉onCreateView()所创建的对象。

  • 解决方案

onDestroyView()里面调用recyclerView.setAdapter(null)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值