remove fragment in viewPager2 use FragmentStateAdapter, but still display
Finally, it works for me. when we call notifyDataSetChanged()
, android will callmethod getItemId()
in adapter, to check if the item has been updated or not. it returns the position in source code. which means in list 0..i..n
, if you remove i
, it becomes to 0...i...n-1
, the i
won't change and the data won't update in adater.
/** * Default implementation works for collections that don't add, move, remove items. * <p> * TODO(b/122670460): add lint rule * When overriding, also override {@link #containsItem(long)}. * <p> * If the item is not a part of the collection, return {@link RecyclerView#NO_ID}. * * @param position Adapter position * @return stable item id {@link RecyclerView.Adapter#hasStableIds()} */@Overridepublic long getItemId(int position) { return position;}
what you need to do is rewrite this method and containsItem(long)
,
for my case, I use the hashcode of each fragment:
class TipsAdapter( private val items: MutableList<TripPreferencesOptimizerPage>, context: FragmentActivity ) : FragmentStateAdapter(context) {private val fragmentFactory = context.supportFragmentManager.fragmentFactoryprivate val classLoader = context.classLoaderprivate val pageIds= items.map { it.hashCode().toLong() }override fun getItemCount(): Int = items.sizeoverride fun createFragment(position: Int): Fragment { val pageInfo = items[position] val fragment = fragmentFactory.instantiate(classLoader, pageInfo.fragmentClass.name) fragment.arguments = Bundle().also { it.putParcelable(PAGE_INFO, pageInfo) } return fragment}fun getFragmentName(position: Int) = items[position].fragmentClass.simpleNamefun removeFragment(position: Int) { items.removeAt(position) notifyItemRangeChanged(position, items.size) notifyDataSetChanged()}override fun getItemId(position: Int): Long { return items[position].hashCode().toLong() // make sure notifyDataSetChanged() works}override fun containsItem(itemId: Long): Boolean { return pageIds.contains(itemId)}}