Android深入FragmentStateAdapter

「这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

FragmentPagerAdapter与FragmentStateAdapter的区别

使用FragmentPagerAdapter 时,Fragment对象会一直存留在内存中,所以数据不能过多,FragmentPagerAdapter 适用于只有数量少的页面,例如选项卡。

FragmentStatePagerAdapter

当页面数据很多的时候就可以考虑使用FragmentStatePagerAdapte

源码简单解读

onCreateViewHolder()方法

public final FragmentViewHolder onCreateViewHolder (@NonNull ViewGroup parent,int viewType){
    return FragmentViewHolder.create(parent);
}
static FragmentViewHolder create (ViewGroup parent){
    FrameLayout container = new FrameLayout(parent.getContext());
    container.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    container.setId(ViewCompat.generateViewId());
    container.setSaveEnabled(false);
    return new FragmentViewHolder(container);
}
复制代码

onCreateViewHolder()创建一个宽高都 MATCH_PARENT 的 FrameLayout,注意这 里并不像 PagerAdapter 是 Fragment 的 rootView;

onBindViewHolder()

public final void onBindViewHolder(final @NonNull FragmentViewHolder holder, int position) {
    final long itemId = holder.getItemId();
    final int viewHolderId = holder.getContainer().getId();
    final Long boundItemId = itemForViewHolder(viewHolderId); // item currently bound to the VH
    if (boundItemId != null && boundItemId != itemId) {
        removeFragment(boundItemId);
        525 mItemIdToViewHolder.remove(boundItemId);
    } mItemIdToViewHolder.put(itemId, viewHolderId);
    // 这可能会覆盖现有条目
    // 保证目标 Fragment 不为空,意思是可以提前创建 ensureFragment(position);
    /** Special case when {@link RecyclerView} decides to keep the {@link container} *
     attached to the window, but not to the view hierarchy (i.e. parent is null) */
    final FrameLayout container = holder.getContainer();
    // 如果 ItemView 已经在添加到 Window 中,且 parent 不等于 null,会触发绑定 viewHoder 操作;
    if (ViewCompat.isAttachedToWindow(container)) {
        if (container.getParent() != null) {
            throw new IllegalStateException("Design assumption violated.");
        }
        container.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                if (container.getParent() != null) {
                    container.removeOnLayoutChangeListener(this); //将 Fragment 和 ViewHolder 绑定 
                    placeFragmentInViewHolder(holder);
                }
            }
        });
    }
    //回收垃圾 
     Fragments gcFragments(); 
}
复制代码

onBindViewHolder()首先会获取当前 position 对应的 Fragment,这意味着预加载的 Fragment 对象会提前创建;
如果当前的 holder.itemView 已经添加到屏幕且已经布局且 parent 不等于空,就会将Fragment 绑定到ViewHodler; 每次调用都会 gc 一次,主要的避免用户修改数据源造成垃圾对象;

onViewAttachedToWindow()

public final void onViewAttachedToWindow ( 
@NonNull final FragmentViewHolder holder){
    placeFragmentInViewHolder(holder);
    gcFragments();
}
复制代码

onViewAttachedToWindow()方法调用 onViewAttachedToWindow将Fragment和hodler绑定

onViewRecycled()

public final void onViewRecycled (@NonNull FragmentViewHolder holder){
    final int viewHolderId = holder.getContainer().getId();
    final Long boundItemId = itemForViewHolder(viewHolderId);
    // 当前绑定到VH的项目
    if (boundItemId != null) {
        removeFragment(boundItemId);
        mItemIdToViewHolder.remove(boundItemId);
    }
}
复制代码

当 onViewRecycled()时才会触发 Fragment 移除

Fragment懒加载

懒加载效果

setoffscreenPageLimit(0); 
复制代码

Fragment 中监听不到 setUserVisibleHint 在设置 offscreenPageLimit>0 时,Fragment 中是监听不到 setUserVisibleHint 调用的,源码里面没有调用,而且该方法被标记过时,所以,适用于 ViewPager 那一套懒加载 Fragment 在这里是不行的;

在遇到 offscreenPageLimit>0 时,处理离屏 Fragment 和 可见 Fragment 没有什么区别,所以无法通过 setUserVisibleHint 判断显示与否,这一点知得注意.

猜你喜欢

转载自juejin.im/post/7036344431875719182
今日推荐