Android组件之Fragment(三)---实战知识
本文在前面Fragment系列文章的基础上,重在想要从源码和实践运用的角度,去学习、分析、总结Fragment一些新技术函数和组件。
1.setUserVisibleHint与setMaxLifecycle
1.1 废弃原因
我们先看一下最新的setUserVisibleHint方法的注释
* Set a hint to the system about whether this fragment's UI is currently visible * to the user. This hint defaults to true and is persistent across fragment instance * state save and restore. * <p>An app may set this to false to indicate that the fragment's UI is * scrolled out of visibility or is otherwise not directly visible to the user. * This may be used by the system to prioritize operations such as fragment lifecycle updates * or loader ordering behavior.</p> * <p><strong>Note:</strong> This method may be called outside of the fragment lifecycle. * and thus has no ordering guarantees with regard to fragment lifecycle method calls.</p> * @param isVisibleToUser true if this fragment's UI is currently visible to the user (default), * false if it is not. * @deprecated If you are manually calling this method, use * {@link FragmentTransaction#setMaxLifecycle(Fragment, Lifecycle.State)} instead. If * overriding this method, behavior implemented when passing in <code>true</code> should be * moved to {@link Fragment#onResume()}, and behavior implemented when passing in * <code>false</code> should be moved to {@link Fragment#onPause()}. @Deprecated public void setUserVisibleHint(boolean isVisibleToUser) { if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && mFragmentManager != null && isAdded() && mIsCreated) { mFragmentManager.performPendingDeferredStart( mFragmentManager.createOrGetFragmentStateManager(this)); mUserVisibleHint = isVisibleToUser; mDeferStart = mState < STARTED && !isVisibleToUser; if (mSavedFragmentState != null) { // Ensure that if the user visible hint is set before the Fragment has // restored its state that we don't lose the new value mSavedUserVisibleHint = isVisibleToUser;通过方法注释,我们知道以下几点信息:
1.setUserVisibleHint已经废弃,不建议使用,废弃原因的话,就是之前Fragment原理分析文章中讲到的,此函数的回调可能发生在生命周期之前,建议使用setMaxLifecycle方法替代,从方法名可知,这个方法是设置fragment最大生命周期的
2.对于之前使用setUserVisibleHint的代码,官方进行如下修改,将fragment不可见(即isVisibleToUser==false)
的代码,移到Fragment#onPause()中,将fragment可见(即isVisibleToUser==true)
的代码,移到Fragment#onResume()中。不妨先猜想一下,这个函数既然是设置每个fragment的最大生命周期的,提出也是为了解决setUserVisibleHint与fragment生命周期不同步的问题,那么是否是代表,通过设置这个,就可以控制fragment展示的生命周期?带着这个疑问,继续看。
1.2 源码中理解,如何用?
好了,看到这里,我们知道官方为什么废弃它,以及提供的替代方法了,接下来就是怎么用的问题了。从方法注释看,
* Constructor for {@link FragmentPagerAdapter} that sets the fragment manager for the adapter. * This is the equivalent of calling {@link #FragmentPagerAdapter(FragmentManager, int)} and * passing in {@link #BEHAVIOR_SET_USER_VISIBLE_HINT}. * <p>Fragments will have {@link Fragment#setUserVisibleHint(boolean)} called whenever the * current Fragment changes.</p> * @param fm fragment manager that will interact with this adapter * @deprecated use {@link #FragmentPagerAdapter(FragmentManager, int)} with * {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} @Deprecated public FragmentPagerAdapter(@NonNull FragmentManager fm) { this(fm, BEHAVIOR_SET_USER_VISIBLE_HINT); * Constructor for {@link FragmentPagerAdapter}. * If {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} is passed in, then only the current * Fragment is in the {@link Lifecycle.State#RESUMED} state. All other fragments are capped at * {@link Lifecycle.State#STARTED}. If {@link #BEHAVIOR_SET_USER_VISIBLE_HINT} is passed, all * fragments are in the {@link Lifecycle.State#RESUMED} state and there will be callbacks to * {@link Fragment#setUserVisibleHint(boolean)}. * @param fm fragment manager that will interact with this adapter * @param behavior determines if only current fragments are in a resumed state public FragmentPagerAdapter(@NonNull FragmentManager fm, @Behavior int behavior) { mFragmentManager = fm; mBehavior = behavior;use {@link FragmentTransaction#setMaxLifecycle(Fragment, Lifecycle.State)} instead
,这好像有点问题了,像我们自己通过FragmentManager管理fragment的情况,还可以这样调用,但是大家更多的时候,是使用viewpager+fragment的方案实现多页面,而ViewPagerAdapter已经帮我们在源码中自动管理了fragment,这怎么办,难道要修改源码?别着急,官方已经给我们提供了相关方法。
FragmentPagerAdapter的另外一个构造方法
正常我们使用FragmentPagerAdapter实现自定义的PagerAdapter时,一般只是重写了第一个构造方法(即:只是吧fragmentManager传给了adapter),可以看到实际上,它也是调用了另外一个构造方法,传入了参数
BEHAVIOR_SET_USER_VISIBLE_HINT
。
我们通过方法注释,可以先了解一下这些int值代表的含义@Retention(RetentionPolicy.SOURCE) @IntDef({BEHAVIOR_SET_USER_VISIBLE_HINT, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT}) private @interface Behavior { } * Indicates that {@link Fragment#setUserVisibleHint(boolean)} will be called when the current * fragment changes. * @deprecated This behavior relies on the deprecated * {@link Fragment#setUserVisibleHint(boolean)} API. Use * {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} to switch to its replacement, * {@link FragmentTransaction#setMaxLifecycle}. * @see #FragmentPagerAdapter(FragmentManager, int) * 设置为BEHAVIOR_SET_USER_VISIBLE_HINT,setUserVisibleHint方法将被调用 * 设置为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,setMaxLifecycle方法将被调用 @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; * Indicates that only the current fragment will be in the {@link Lifecycle.State#RESUMED} * state. All other Fragments are capped at {@link Lifecycle.State#STARTED}. * @see #FragmentPagerAdapter(FragmentManager, int) public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1;
也就是说,ViewPagerAdapter内部是通过这个值来区分调用setMaxLifecycle还是setUserVisibleHint的,接下来我们看一下FragmentPagerAdapter源码,是否是这么一回事儿。
FragmentPagerAdapter#instantiateItem#setPrimaryItem
由上一篇fragment文章可知,fragmentpageradapter中最主要的几个方法就是instantiateItem和setPrimaryItem,分别用作初始化当前fragment、设置当前fragment,所以我们看一下这两个方法,是否做了相关函数的区分调用。@NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); final long itemId = getItemId(position); // Do we already have this fragment? String name = makeFragmentName(container.getId(), itemId); Fragment fragment = mFragmentManager.findFragmentByTag(name); if (fragment != null) { if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); mCurTransaction.attach(fragment); } else { fragment = getItem(position); if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId)); if (fragment != mCurrentPrimaryItem) { fragment.setMenuVisibility(false); //看这儿,的确区分了 if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED); } else { fragment.setUserVisibleHint(false); return fragment; @Override public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) { Fragment fragment = (Fragment)object; if (fragment != mCurrentPrimaryItem) { if (mCurrentPrimaryItem != null) { mCurrentPrimaryItem.setMenuVisibility(false); //看这儿,的确区分了 if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED); } else { mCurrentPrimaryItem.setUserVisibleHint(false); fragment.setMenuVisibility(true); //看这儿,的确区分了 if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED); } else { fragment.setUserVisibleHint(true); mCurrentPrimaryItem = fragment;
看到这里,也就是说如果我们调用构造方法,传入BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,那么FragmentPagerAdapter默认创建fragment的时候,将帮我们提交的时候,提交为
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED)
1.3 Lifecycle.State不同的状态代表什么?
直接看一下Lifecycle.State.RESUMED的源码注释,我们看一下这个代表什么。
* Lifecycle states. You can consider the states as the nodes in a graph and * {@link Event}s as the edges between these nodes. @SuppressWarnings("WeakerAccess") public enum State { * Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch * any more events. For instance, for an {@link android.app.Activity}, this state is reached * <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call. * 销毁状态 DESTROYED, * Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is * the state when it is constructed but has not received * {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet. * 初始状态 INITIALIZED, * Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached in two cases: * <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call; * <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call. * </ul> * 已创建状态 * 从函数注释看,分为两种情况 * 一种是在当前fragment的状态还小于onCreate,则正常走到onCreate * 一种是在当前fragment的状态大于onCreate,则会使fragment的生命周期走到onStop CREATED, * Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached in two cases: * <li>after {@link android.app.Activity#onStart() onStart} call; * <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call. * </ul> * 创建并启动,可见不可操作 * 从函数注释看,分为两种情况 * 一种是在当前fragment的状态还小于onStart,则正常走到onStart * 一种是在当前fragment的状态大于onStart,则会使fragment的生命周期走到onPause STARTED, * Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached after {@link android.app.Activity#onResume() onResume} is called. * fragment的onResume生命周期在Activity#onResume()生命周期之后 * 创建启动并可操作 * 也就是viewPager中,针对于缓存的fragment,如果设置了这个生命周期,则保证fragment的onResume是在fragment可见之后才去执行 RESUMED;针对于这几种状态,去通过FragmentTransaction去进行fragment生命周期操作,针对于fragment当前状态,结合设置的最大生命周期,执行相应生命周期。
迫不及待的通过Demo验证一下:package com.itbird.fragment; import android.view.View; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager2.adapter.FragmentStateAdapter; * Created by itbird on 2022/3/18 public class MyFragmentPagerAdapter extends FragmentPagerAdapter { private final int PAGER_COUNT = 4; Fragment fragment1; Fragment fragment2; Fragment fragment3; Fragment fragment4; public MyFragmentPagerAdapter(@NonNull FragmentManager fm, int behavior) { super(fm, behavior); fragment1 = BlankFragment1.newInstance("name1", "age1"); fragment2 = BlankFragment2.newInstance("name2", "age2"); fragment3 = BlankFragment3.newInstance("name3", "age3"); fragment4 = BlankFragment4.newInstance("name4", "age4"); public MyFragmentPagerAdapter(@NonNull FragmentManager fm) { super(fm); fragment1 = BlankFragment1.newInstance("name1", "age1"); fragment2 = BlankFragment2.newInstance("name2", "age2"); fragment3 = BlankFragment3.newInstance("name3", "age3"); fragment4 = BlankFragment4.newInstance("name4", "age4"); @Override public int getCount() { return PAGER_COUNT; @NonNull @Override public Fragment getItem(int position) { Fragment fragment = null; switch (position) { case 0: fragment = fragment1; break; case 1: fragment = fragment2; break; case 2: fragment = fragment3; break; case 3: fragment = fragment4; break; return fragment; @Override public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { return super.isViewFromObject(view, object);
运行一下:
日志看一下生命周期
2022-03-25 16:07:51.452 21151-21151/? I/zygote: Late-enabling -Xcheck:jni 2022-03-25 16:07:51.486 21151-21151/? W/zygote: Unexpected CPU variant for X86 using defaults: x86 2022-03-25 16:07:51.831 21151-21151/com.itbird E/FragmenViewPagerTestActivity: FragmenViewPagerTestActivity onCreate 2022-03-25 16:07:51.846 21151-21151/com.itbird D/FragmenViewPagerTestActivity: onStart 2022-03-25 16:07:51.853 21151-21151/com.itbird D/FragmenViewPagerTestActivity: onResume 2022-03-25 16:07:51.873 21151-21172/com.itbird D/OpenGLRenderer: HWUI GL Pipeline 2022-03-25 16:07:51.928 21151-21151/com.itbird D/BlankFragment1: onAttach 2022-03-25 16:07:51.930 21151-21151/com.itbird D/BlankFragment1: onCreate 2022-03-25 16:07:51.930 21151-21151/com.itbird D/BlankFragment1: onCreateView 2022-03-25 16:07:51.937 21151-21151/com.itbird D/BlankFragment1: onViewCreated 2022-03-25 16:07:51.937 21151-21151/com.itbird D/BlankFragment1: onActivityCreated 2022-03-25 16:07:51.938 21151-21151/com.itbird D/BlankFragment1: onStart //如我们所料,BlankFragment2在不可见状态下,也就是缓存状态下,只执行到onStart 2022-03-25 16:07:51.939 21151-21151/com.itbird D/BlankFragment2: onAttach 2022-03-25 16:07:51.940 21151-21151/com.itbird D/BlankFragment2: onCreate 2022-03-25 16:07:51.940 21151-21151/com.itbird D/BlankFragment2: onCreateView 2022-03-25 16:07:51.946 21151-21151/com.itbird D/BlankFragment2: onViewCreated 2022-03-25 16:07:51.947 21151-21151/com.itbird D/BlankFragment2: onActivityCreated 2022-03-25 16:07:51.947 21151-21151/com.itbird D/BlankFragment2: onStart //fragment1正常执行到onResume 2022-03-25 16:07:51.949 21151-21151/com.itbird D/BlankFragment1: onResume
我们这时去滑动到fragment2,应该BlankFragment2的onResume会被调用,BlankFragment1的生命周期不变,BlankFragment3应该会执行到onStart
也许会有人问,我没看到ViewPager哪里设置最大生命周期呀,为什么执行到onStart?大家可以看一下上面1.2
我们说到两个构造方法状态判断的时候,其实已经贴出了。这里再看一下
FragmentPagerAdapter#instantiateItem
@Override public Object instantiateItem(@NonNull ViewGroup container, int position) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); final long itemId = getItemId(position); // Do we already have this fragment? String name = makeFragmentName(container.getId(), itemId); Fragment fragment = mFragmentManager.findFragmentByTag(name); if (fragment != null) { if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); mCurTransaction.attach(fragment); } else { fragment = getItem(position); if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId)); if (fragment != mCurrentPrimaryItem) { fragment.setMenuVisibility(false); //这里,初始化item fragment时,已经设置了为STARTED if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED); } else { fragment.setUserVisibleHint(false); return fragment;
针对于add、remove、hide、show时,不同状态下的fragment操作设置最大生命周期,会带来的不同, 这里就不多赘述了。
对于ViewPager+Fragment实现懒加载,在最新版的FragmentPagerAdapter,可以切换到BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT模式,在Fragment#onResume里判断,更符合显示逻辑2.onHiddenChanged与setUserVisibleHint的区别
onHiddenChanged():对于通过FragmentManager自己管理fragment时,调用show、hide方法,此方法才会回调 。
setUserVisibleHint():对于调用系统ViewPager+Fragment方案,才会回调,但是这时候Fragment不会去调用上面说的onhiddenchanged方法,只会调用setUserVisibleHint这个方法。
3.ViewPager2与ViewPager
* ViewPager2 replaces {@link androidx.viewpager.widget.ViewPager}, addressing most of its * predecessor’s pain-points, including right-to-left layout support, vertical orientation, * modifiable Fragment collections, etc. * @see androidx.viewpager.widget.ViewPager public final class ViewPager2 extends ViewGroup {从文档注释来看ViewPager2确实是用来替代ViewPager 的,顺带解决之前ViewPager的一些问题,并且加入了 RTL,竖向滚动支持。
3.1 新功能&API的变动
我们先来看看有哪些功能和使用上的变化:
支持RTL布局
支持竖向滚动
完整支持notifyDataSetChangedAPI的变动:
FragmentStateAdapter替换了原来的 FragmentStatePagerAdapter
RecyclerView.Adapter替换了原来的 PagerAdapter
registerOnPageChangeCallback替换了原来的 addPageChangeListener看了上面这些介绍,有一点比较吸引人的就是支持竖向滚动了,这是怎么实现的呢?ViewPager2的源码不长,我们来简单分析一下。
3.2 源码解析
通过查看源码得知,ViewPager2是直接继承ViewGroup的,意味着和ViewPager不兼容,类注释上也写了它的作用是取代ViewPager,不过短时间内ViewPager应该还不会被废弃掉。
继续查看源码,发现了两个比较重要的成员变量:public final class ViewPager2 extends ViewGroup { int mCurrentItem; boolean mCurrentItemDirty = false; private RecyclerView.AdapterDataObserver mCurrentItemDataSetChangeObserver = new DataSetChangeObserver() { @Override public void onChanged() { mCurrentItemDirty = true; mScrollEventAdapter.notifyDataSetChangeHappened(); private LinearLayoutManager mLayoutManager; RecyclerView mRecyclerView; private PagerSnapHelper mPagerSnapHelper; ScrollEventAdapter mScrollEventAdapter; private PageTransformerAdapter mPageTransformerAdapter; private RecyclerView.ItemAnimator mSavedItemAnimator = null; public ViewPager2(@NonNull Context context) { super(context); initialize(context, null);
很清楚得知,ViewPager2的核心实现就是RecyclerView+LinearLayoutManager了,因为LinearLayoutManager本身就支持竖向和横向两种布局方式,所以ViewPager2也能很容易地支持这两种滚动方向了,而几乎不需要添加任何多余的代码。
为了让RecyclerView变得像原来的ViewPager,需要设置下SnapHelper:mPagerSnapHelper = new PagerSnapHelperImpl(); mPagerSnapHelper.attachToRecyclerView(mRecyclerView);
熟悉RecyclerView的同学都知道,SnapHelper用于辅助RecyclerView在滚动结束时将Item对齐到某个位置。PagerSnapHelper的作用让滑动结束时使当前Item居中显示,并且 限制一次只能滑动一页,不能快速滑动,这样就和viewpager的交互很像了。
另外和viewpager一样,viewpager2可以承载fragment,我们需要继承实现它提供的
FragmentStateAdapter
public abstract class FragmentStateAdapter extends RecyclerView.Adapter<FragmentViewHolder> implements StatefulAdapter { // State saving config private static final String KEY_PREFIX_FRAGMENT = "f#"; private static final String KEY_PREFIX_STATE = "s#"; // Fragment GC config private static final long GRACE_WINDOW_TIME_MS = 10_000; // 10 seconds @SuppressWarnings("WeakerAccess") // to avoid creation of a synthetic accessor final Lifecycle mLifecycle; @SuppressWarnings("WeakerAccess") // to avoid creation of a synthetic accessor final FragmentManager mFragmentManager; // Fragment bookkeeping @SuppressWarnings("WeakerAccess") // to avoid creation of a synthetic accessor final LongSparseArray<Fragment> mFragments = new LongSparseArray<>(); private final LongSparseArray<Fragment.SavedState> mSavedStates = new LongSparseArray<>(); private final LongSparseArray<Integer> mItemIdToViewHolder = new LongSparseArray<>(); private FragmentMaxLifecycleEnforcer mFragmentMaxLifecycleEnforcer; // Fragment GC @SuppressWarnings("WeakerAccess") // to avoid creation of a synthetic accessor boolean mIsInGracePeriod = false; private boolean mHasStaleFragments = false; * @param fragmentActivity if the {@link ViewPager2} lives directly in a * {@link FragmentActivity} subclass. * @see FragmentStateAdapter#FragmentStateAdapter(Fragment) * @see FragmentStateAdapter#FragmentStateAdapter(FragmentManager, Lifecycle) public FragmentStateAdapter(@NonNull FragmentActivity fragmentActivity) { this(fragmentActivity.getSupportFragmentManager(), fragmentActivity.getLifecycle());
3.3 懒加载
我们在看ViewPager代码的时候,有一个缓冲默认最小为1机制,所以需要实现懒加载,需要借助fragment相应生命周期去自己实现,尽管后来又setMaxLifecycle等函数,但是我们依然会觉得ViewPager本身的缺陷,一直在通过外界来规避。
我们看一下ViewPager2是否已解决这个问题
ViewPager2#setOffscreenPageLimit
public void setOffscreenPageLimit(@OffscreenPageLimit int limit) { if (limit < 1 && limit != OFFSCREEN_PAGE_LIMIT_DEFAULT) { throw new IllegalArgumentException( "Offscreen page limit must be OFFSCREEN_PAGE_LIMIT_DEFAULT or a number > 0"); mOffscreenPageLimit = limit; // Trigger layout so prefetch happens through getExtraLayoutSize() mRecyclerView.requestLayout();
从代码中看到,ViewPager2实际上允许设置limit 为0,只不过会抛出一个异常,但是通过上层来捕获就可以了,但是实际上生效的,也就说缓存为0的效果实现了。不像ViewPager源码中,检测到limit小于1,会强制修改为1。
ViewPager#setOffscreenPageLimit
public static final int DEFAULT_OFFSCREEN_PAGES = 1; public void setOffscreenPageLimit(int limit) { if (limit < DEFAULT_OFFSCREEN_PAGES) { Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + DEFAULT_OFFSCREEN_PAGES); limit = DEFAULT_OFFSCREEN_PAGES; if (limit != mOffscreenPageLimit) { mOffscreenPageLimit = limit; populate();
3.4 局部刷新
从上面的源码分析我们知道,Viewpager2利用recyclerview来实现viewpager的功能,那么自然而然,recyclerview拥有局部刷新的功能,Viewpager2肯定也是有的。
public abstract class FragmentStateAdapter extends RecyclerView.Adapter<FragmentViewHolder> implements StatefulAdapter {}
可以看到FragmentStateAdapter 继承与RecyclerView.Adapter,所以notifyDataSetChanged & notifyItemChanged(int position)两个功能,肯定在FragmentStateAdapter 也拥有了。
1.Fragment中废弃了setUserVisibleHint方法,而是用setMaxLifecycle替代,是因为可以解决Fragment生命周期与可见之前不同步的问题。另外一方面,Google官方也通过此方法,给我们公开了可以控制Fragment生命周期的方法。
2.onHiddenChanged是自己通过FragmentManager管理Fragment时才会调用,ViewPager+Fragment方案管理Fragment时,回调的是setUserVisibleHint方法。
3.Viewpager2利用Recyclerview来实现Viewpager的功能,无疑使使其可扩展性大大提升,代码也变得更优雅简洁,使用起来也更灵活。同时内部也支持实现了懒加载、局部刷新功能。