LayoutInflater的inflate相关问题
参数root
当参数root为null时,attachToRoot参数无效。且生成的view会丢失布局文件中的LayoutParams
当参数root不为null时,生成的view会根据root类型来保留布局文件中对应的LayoutParams
参数attachToRoot
attachToRoot为true时,返回的view就是root
attachToRoot为false时,返回的view是跟布局生成的view
参数root
当参数root为null时,attachToRoot参数无效。且生成的view会丢失布局文件中的LayoutParams
当参数root不为null时,生成的view会根据root类型来保留布局文件中对应的LayoutParams
参数attachToRoot
attachToRoot为true时,返回的view就是root
attachToRoot为false时,返回的view是跟布局生成的view
问题:一个viewpager2使用了FragmentStateAdapter,当系统配置发生变化(切换横竖屏、切换深色模式、切换语言),会多出fragment实例,每切一次就会多一次。查看日志每次切换后获取fragment的时候,都会重新走FragmentStateAdapter的createFragment。而之前已经生成的fragment都会重建。所以造成上面的现象和问题。
原因:这个viewpager2是动态通过代码new创建的,改成直接写在xml布局中就正常了(一般写在xml中都会加一个id的)
根因:只有绑定id的viewpager2才能正常同步fragment。从xml加载的也需要加id才能。代码动态创建的,设置id后也能正确。
private void ensureFragment(int position) {
long itemId = getItemId(position);
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);
}
}FragmentStateAdapter源码显示,只有mFragments不包含的时候,才会从createFragment拿
@Override
public final void restoreState(@NonNull Parcelable savedState) {
if (!mSavedStates.isEmpty() || !mFragments.isEmpty()) {
throw new IllegalStateException(
"Expected the adapter to be 'fresh' while restoring state.");
}
Bundle bundle = (Bundle) savedState;
if (bundle.getClassLoader() == null) {
/** TODO(b/133752041): pass the class loader from {@link ViewPager2.SavedState } */
bundle.setClassLoader(getClass().getClassLoader());
}
for (String key : bundle.keySet()) {
if (isValidKey(key, KEY_PREFIX_FRAGMENT)) {
long itemId = parseIdFromKey(key, KEY_PREFIX_FRAGMENT);
Fragment fragment = mFragmentManager.getFragment(bundle, key);
mFragments.put(itemId, fragment);
continue;
}
if (isValidKey(key, KEY_PREFIX_STATE)) {
long itemId = parseIdFromKey(key, KEY_PREFIX_STATE);
Fragment.SavedState state = bundle.getParcelable(key);
if (containsItem(itemId)) {
mSavedStates.put(itemId, state);
}
continue;
}
throw new IllegalArgumentException("Unexpected key in savedState: " + key);
}
if (!mFragments.isEmpty()) {
mHasStaleFragments = true;
mIsInGracePeriod = true;
gcFragments();
scheduleGracePeriodEnd();
}
}然后可以看见除了ensureFragment,只有在restoreState这个地方mFragments才会存fragment。关键是要从savedState拿到fragment。
继续跟源码可以发现adapter的restoreState方法是在viewpager2的restorePendingState方法中被调用的,其中传递的参数是mPendingAdapterState,继续看看mPendingAdapterState哪儿来的
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
mPendingCurrentItem = ss.mCurrentItem;
mPendingAdapterState = ss.mAdapterState;
}mPendingAdapterState来自于viewpager2的onRestoreInstanceState。
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID) {
Parcelable state = container.get(mID);
if (state != null) {
// Log.i("View", "Restoreing #" + Integer.toHexString(mID)
// + ": " + state);
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
onRestoreInstanceState(state);
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onRestoreInstanceState()");
}
}
}
}可以看见只有当有id的时候才会执行onRestoreInstanceState