目录
- 1. ViewPagerAdapter与其两个子类FragmentPagerAdapter、FragmentStatePagerAdapter
- 1.1. ViewPagerAdapter重要方法剖析
- a. instantiateItem(ViewGroup container, int position)
- b. setPrimaryItem(ViewGroup container, int position, Object object)
- c. startUpdate(@NonNull View container)/finishUpdate(@NonNull ViewGroup container)
- d. destroyItem(@NonNull View container, int position, @NonNull Object object)
- 1.2. FragmentPagerAdapter剖析
- a. 重写instantiateItem()方法,通过mFragmentManager来创建Fragment
- b. 重写setPrimaryItem()方法,设置主Fragment的生命周期为RESUMED,将即将隐藏的原主Fragment的生命周期降级为STARTED
- 1.3. FragmentStatePagerAdapter剖析
- a. instantiateItem()方法的不同实现
- b. setPrimaryItem()的实现与FragmentPagerAdapter类中的实现是相同的
- c. 重写saveState()
- d. 重写restoreState()方法
- 2. FragmentStateAdapter
- a. 重写onCreateViewHolder()
- b. 重写onBindViewHolder()
- c. 重写onViewAttachedToWindow()方法
- d. 重写onAttachedToRecyclerView()方法
- e. 重写onViewRecycled()方法
- f. 实现StatefulAdapter接口的saveState()方法和restoreState()方法
- Notice
1. ViewPagerAdapter与其两个子类FragmentPagerAdapter、FragmentStatePagerAdapter
1.1. ViewPagerAdapter重要方法剖析
a. instantiateItem(ViewGroup container, int position)
该方法的作用是根据position创建页面,container用于承载被添加的View。
b. setPrimaryItem(ViewGroup container, int position, Object object)
该方法的作用是通知ViewPagerAdapter当前的主page,即展示给用户的当前页面。
c. startUpdate(@NonNull View container)/finishUpdate(@NonNull ViewGroup container)
这两个方法总是成对被调用的,调用时机是展示页面发生变化时。
d. destroyItem(@NonNull View container, int position, @NonNull Object object)
这个方法的调用时机是ViewPager从其类型为ArrayList的成员变量mItems中remove一个对象时,然后通过调用ViewPagerAdapter的destroyItem()方法将container中的View删除。
总结一下:以上几个方法基本上都是在ViewPager中的populate()方法中被调用的,其时序为:
1.2. FragmentPagerAdapter剖析
该适配器继承自PagerAdapter,主要实现了每个页面是Fragment情况的适配工作,内部通过FragmentManager来管理各个Fragment。只要用户还可以返回到某个页面,该Fragment就会永久保留在片段管理器中。主要工作有两个:
a. 重写instantiateItem()方法,通过mFragmentManager来创建Fragment
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) {
//如果mFragmentManager中已经存在当前Fragment,则开启一个 ATTATCH事务
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
//如果mFragmentManager中不存在当前Fragmen,则需要创建一个Fragment,并开启一个ADD事务
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
//如果此Fragment不是主Fragm,需根据mBehavior来对Fragment的生命周期降级
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
//最多会执行到onStart()回调
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
} else {
//采用原来的setUserVisibleHint(false)处理方式,//注意此处传入参数为false
fragment.setUserVisibleHint(false);
}
}
return fragment;
}
b. 重写setPrimaryItem()方法,设置主Fragment的生命周期为RESUMED,将即将隐藏的原主Fragment的生命周期降级为STARTED
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Fragment fragment = (Fragment)object;
//
if (fragment != mCurrentPrimaryItem) {
//当mCurrentPrimaryItem != null时,原主Fragment即将隐藏
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);
//将主Fragement的生命周期设置为RESUMED
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED);
} else {
//注意此处传入参数为true
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
1.3. FragmentStatePagerAdapter剖析
该适配器也继承自PagerAdapter,其功能和FragmentPagerAdapter类似,主要也是重写instantiateItem()方法和setPrimaryItem()方法通过FagmentManager来管理Fragment。与其不同的是FragmentStatePagerAdapter还是实现了Fragment的缓存功能,通过类型为ArrayListy的成员变量mSavedState和mFragments来实现。
a. instantiateItem()方法的不同实现
public Object instantiateItem(@NonNull ViewGroup container, int position) {
//如果能从mFragments缓存中拿到该position对应的Fragment立即返回该Fagement
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
//如果mFragments缓存中不存在该position对应的Fragment,则通过getItem()创建一个Fragment
Fragment fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
if (mSavedState.size() > position) {
//如果mSavedState缓存中存在该position对应的SavedState对象,则将该对象赋值给新创建的Fragment的mSavedFragmentState变量,
//用于该新Fragment恢复原来的数据。
Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
while (mFragments.size() <= position) {
mFragments.add(null);
}
fragment.setMenuVisibility(false);
//原处理方式setUserVisibleHint(false)
if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) {
fragment.setUserVisibleHint(false);
}
// 将当前Fragment缓存在mFragments列表中
mFragments.set(position, fragment);
mCurTransaction.add(container.getId(), fragment);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
}
return fragment;
}
b. setPrimaryItem()的实现与FragmentPagerAdapter类中的实现是相同的
c. 重写saveState()
ViewPager重写了View的onSaveInstanceState()方法,在该方法中又会调用FragmentStatePagerAdapter的saveState()来将mSavedState与mFragments存储在Bundle对象中。
public Parcelable saveState() {
Bundle state = null;
//存储mSavedState
if (mSavedState.size() > 0) {
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
//存储mFragments
for (int i=0; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
return state;
}
d. 重写restoreState()方法
ViewPager重写了View的onRestoreInstanceState()方法,在该方法中又会调用FragmentStatePagerAdapter的restoreState()方法来恢复存储在Bundle中的mSavedState与mFragments对象。代码逻辑与saveState()是相对应的。
2. FragmentStateAdapter
FragmentStateAdapter继承自RecyclerView.Adapter,下面看一下关键方法的实现。
a. 重写onCreateViewHolder()
返回一个FragmentViewHolder对象,该FragmentViewHolder的根布局为FrameLayout,即itemView为FrameLayout对象。
b. 重写onBindViewHolder()
重写该方法主要做三件事:
- 更新mItemIdToViewHolder
- 创建Fragment
- 垃圾回收无用Fragment
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);
mItemIdToViewHolder.remove(boundItemId);
}
//1. 更新mItemIdToViewHolder
mItemIdToViewHolder.put(itemId, viewHolderId); // this might overwrite an existing entry
//2. 创建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();
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);
placeFragmentInViewHolder(holder);
}
}
});
}
//3. 垃圾回收无用Fragment
gcFragments();
}
在ensureFragment()方法中会调用createFragment()虚方法来创建Fragment,需要通过子类实现自己的创建逻辑:
private void ensureFragment(int position) {
long itemId = getItemId(position);
//当没有position对应的Fragment时才创建
if (!mFragments.containsKey(itemId)) {
// TODO(133419201): check if a Fragment provided here is a new Fragment
Fragment newFragment = createFragment(position);
newFragment.setInitialSavedState(mSavedStates.get(itemId));
mFragments.put(itemId, newFragment);
}
}
mFragments成员变量缓存了所以使用过的Fragment,gcFragments() 方法在几处被调用,在绑定ViewHolder时是触发垃圾回收的时机之一:
void gcFragments() {
if (!mHasStaleFragments || shouldDelayFragmentTransactions()) {
return;
}
// Remove Fragments for items that are no longer part of the data-set
//对于position不在[0, getItemCount()]内的Fragment应该删除
Set<Long> toRemove = new ArraySet<>();
for (int ix = 0; ix < mFragments.size(); ix++) {
long itemId = mFragments.keyAt(ix);
if (!containsItem(itemId)) {
toRemove.add(itemId);
mItemIdToViewHolder.remove(itemId); // in case they're still bound
}
}
// Remove Fragments that are not bound anywhere -- pending a grace period
//对于没有被绑定到ViewHolder中的Fragment应该删除
if (!mIsInGracePeriod) {
mHasStaleFragments = false; // we've executed all GC checks
for (int ix = 0; ix < mFragments.size(); ix++) {
long itemId = mFragments.keyAt(ix);
if (!isFragmentViewBound(itemId)) {
toRemove.add(itemId);
}
}
}
for (Long itemId : toRemove) {
removeFragment(itemId);
}
}
c. 重写onViewAttachedToWindow()方法
重写该方法做两件事:
- 将Fragement添加到ViewHolder中
- 垃圾回收无用Fragment
public final void onViewAttachedToWindow(@NonNull final FragmentViewHolder holder) {
placeFragmentInViewHolder(holder);
gcFragments();
}
d. 重写onAttachedToRecyclerView()方法
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
checkArgument(mFragmentMaxLifecycleEnforcer == null);
mFragmentMaxLifecycleEnforcer = new FragmentMaxLifecycleEnforcer();
mFragmentMaxLifecycleEnforcer.register(recyclerView);
}
主要是构造一个FragmentMaxLifecycleEnforcer对象,并将recyclerView注册给该对象,管理当前主Fragment与其余非主Fragment的生命周期,主要通过其updateFragmentMaxLifecycle()方法来实现:
void updateFragmentMaxLifecycle(boolean dataSetChanged) {
//删除部分状态判断代码
//...
long currentItemId = getItemId(currentItem);
if (currentItemId == mPrimaryItemId && !dataSetChanged) {
return; // nothing to do
}
Fragment currentItemFragment = mFragments.get(currentItemId);
if (currentItemFragment == null || !currentItemFragment.isAdded()) {
return;
}
mPrimaryItemId = currentItemId;
FragmentTransaction transaction = mFragmentManager.beginTransaction();
//寻找即将resume的Fragment
Fragment toResume = null;
for (int ix = 0; ix < mFragments.size(); ix++) {
long itemId = mFragments.keyAt(ix);
Fragment fragment = mFragments.valueAt(ix);
if (!fragment.isAdded()) {
continue;
}
//对于不是寻找的对象,即将其最大生命周期设置为STARTED
if (itemId != mPrimaryItemId) {
transaction.setMaxLifecycle(fragment, STARTED);
} else {
toResume = fragment; // itemId map key, so only one can match the predicate
}
fragment.setMenuVisibility(itemId == mPrimaryItemId);
}
//将寻找到的Fragment的最大生命周期设置为RESUMED
if (toResume != null) { // in case the Fragment wasn't added yet
transaction.setMaxLifecycle(toResume, RESUMED);
}
if (!transaction.isEmpty()) {
transaction.commitNow();
}
}
e. 重写onViewRecycled()方法
RecyclerView在回收ViewHolder并将其添加到Pools中时会调用onViewRecycled()方法,FragmentStateAdapter重写该方法将缓存对象从mFragments和mItemIdToViewHolder中删除:
public final void onViewRecycled(@NonNull FragmentViewHolder holder) {
final int viewHolderId = holder.getContainer().getId();
final Long boundItemId = itemForViewHolder(viewHolderId); // item currently bound to the VH
if (boundItemId != null) {
removeFragment(boundItemId);
mItemIdToViewHolder.remove(boundItemId);
}
}
f. 实现StatefulAdapter接口的saveState()方法和restoreState()方法
和FragmentStatePagerAdapter一样,StatefulAdapter也有两个成员变量mFagment和mSavedStates,实现这两个方法主要是为了存储和恢复mFagment/mSavedStates。
Notice
- FragmentStateAdapter的内部维护了一个fragmens数组,对于单个Fragment的创建其暴露给使用者来实现,然而Fragment的销毁也是其在内部维护的,外部不知道何时销毁Fragment。这就没有FragmentStatePagerAdapter使用起来方便了,其不仅暴露了创建Fragment的方法instantiateItem(),而且还暴露了Fragment销毁的方法destroyItem(),因此开发人员可以自己在其子类维护一个fragments数组。