问题
I am using ViewPager2 with FragmentStateAdapter and i am calling notifyItemChanged(position). But as expected createFragment method not calling again. Is it is the intended behavior or bug, what should I do
My Code is
class EEditionPagerAdapter(
fragmentManager: FragmentManager, lifecycle: Lifecycle, private var date: String
) : FragmentStateAdapter(fragmentManager, lifecycle) {
private var menuList = emptyList<EEditionMenu>()
override fun getItemCount(): Int = menuList.size
override fun createFragment(position: Int): Fragment {
val menu = menuList[position]
return EEditionListingFragment.newInstance(menu, date)
}
fun submitList(list: List<EEditionMenu>) {
menuList = list
notifyItemRangeChanged(0, menuList.size)
}
fun changeDate(date: String, position: Int){
this.date = date
notifyItemChanged(position)
}
}
回答1:
When you call notifyItemChanged for FragmentStateAdapter it call ensureFragment(position)
that restores the fragment if it has already been created
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);
}
}
Try to override onBindViewHolder and set Date to fragment
override fun onBindViewHolder(
holder: FragmentViewHolder,
position: Int,
payloads: MutableList<Any>
) {
super.onBindViewHolder(holder, position, payloads)
val fragment: EEditionListingFragment? = fragmentManager.findFragmentByTag("f$position") as EEditionListingFragment?
fragment.updateDate(date)
}
回答2:
The fragment put to the mFragment in FragementStateAdapter.class is managed by the
void placeFragmentInViewHolder(@NonNull final FragmentViewHolder holder)
method, which is package private and we do not have access and in this method the fragment is added to the mFragment manager with tag "f" + holder.getItemId()
which is the same as "f" + position
.
scheduleViewAttach(fragment, container);
mFragmentManager.beginTransaction()
.add(fragment, "f" + holder.getItemId())
.setMaxLifecycle(fragment, STARTED)
.commitNow();
mFragmentMaxLifecycleEnforcer.updateFragmentMaxLifecycle(false);
For this reason, we can override the onBindViewHolder
method while a fragement shall be displayed.
@Override
public void onBindViewHolder(@NonNull FragmentViewHolder holder, int position, @NonNull List<Object> payloads) {
super.onBindViewHolder(holder, position, payloads);
if (position == 0) {
String fragmentTag = "f" + holder.getItemId();
Log.v(TAG,"fragmentTag is : " + fragmentTag);
MyFragment fragment0 = (MyFragment) this.mFragmentManger.findFragmentByTag(fragmentTag);
if (fragment0 != null) {
Log.v(TAG,"onBindViewHolder updating fragment ...");
// do what ever you want to update the MyFragment
fragment0.update(payloads);
} else {
Log.v(TAG,"onBindViewHolder called, but fragment0 is null!");
}
}
}
In my case the this.mFragmentManager
is cashed through the constructor.
public MyFragmentStateAdapter(@NonNull Fragment fragment) {
super(fragment); // this calls the fragment.getChildFragmentManager().
this.mFragmentManger = fragment.getChildFragmentManager();
}
And the createFragment()
is:
@NonNull
@Override
public Fragment createFragment(int position) {
if(position == 0){
if (this.fragment0 == null) {
this.fragment0 = MyFragment.getInstance();
}
return this.fragment0;
} else {
Log.v(TAG, "position " + position + " is called");
return null;
}
}
Finally, call the update in somewhere else to trigger the update:
ViewPager2.getAdapter().notifyItemChanged(0, null);
// 0 is the fragment position of the fragment0 and null is payload.
回答3:
FragmentStateAdapter uses item IDs to determine if a fragment has already been created and reuses already created ones. By default, an item ID is the item's position. You can override getItemId
and containsItem
to provide your own unique IDs based on positions and dates, then it will ask for a new fragment when the date changes.
来源:https://stackoverflow.com/questions/60408236/fragmentstateadapter-for-viewpager2-notifyitemchanged-not-working-as-expected