I have a viewPager2 and FragmentStateAdapter, and there are Fragement1, 2,3 4, I am in fragment2, and want to remove fragment3, and display fragment4 after fragment2. The proble
Finally, it works for me. when we call notifyDataSetChanged()
, android will call
method 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()}
*/
@Override
public 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.fragmentFactory
private val classLoader = context.classLoader
private val pageIds= items.map { it.hashCode().toLong() }
override fun getItemCount(): Int = items.size
override 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.simpleName
fun 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)
}
}