Reputation: 57
I need to swap two adapters inside the ConcatAdapter
but the list of adapters that is returned by getAdapters()
is immutable and won't let me use the java.util.Collections
utility.
So far what I've tried was to turn that list into a mutable list, swap the items and set the list back but it's ugly to look at since I'm doing this inside the ItemTouchHelper
's callback.
Would copying the class from the source and make that list mutable instead work? Are there any better solutions?
Upvotes: 1
Views: 733
Reputation: 40878
Instead of the Anti-pattern of hitting private API fields with reflections, we can exchange the underlying data of both adapters and then notifyItemChanged()
.
An adapter in the ConcatAdapter
has a data class item, you can expose it to caller to be modified.
Here's a demo:
// we need to swap adapter at pos1 with adapter at pos2 from contactAdapter
private fun swapAdapters(pos1:Int, pos2:Int) {
// assuming the RV adapter is MyRVAdapter, and holds "data" field
val adapter1 = concatAdapter.adapters[pos1] as MyRVAdapter
val adapter2 = concatAdapter.adapters[pos2] as MyRVAdapter
// Exchange adapters data
val data1 = adapter1.data.copy()
val data2 = adapter2.data.copy()
adapter1.data = data2
adapter2.data = data1
// reflect the change
concatAdapter.notifyItemChanged(pos1)
concatAdapter.notifyItemChanged(pos2)
}
Upvotes: 0
Reputation: 57
I tried to do some hacky stuff with reflection, the ConcatAdapter class doesn't hold a reference to the underlying adapters but there's a ConcatAdapterController field (which class is private) that has a mWrappers
field which is basically the one returned by getAdapters()
Anyway here's the code I've used and it's working fine
val controllerClass = Class.forName("androidx.recyclerview.widget.ConcatAdapterController")
val controllerField = ConcatAdapter::class.java.declaredFields.find { it.name == "mController" }?.apply {
this.isAccessible = true
}
val controller = controllerField?.get(this)
val wrappersField = controllerClass.declaredFields.find { it.name == "mWrappers"}?.apply {
this.isAccessible = true
}
val wrappers = wrappersField?.get(controller) as List<*>
Collections.swap(wrappers, from, to)
notifyItemMoved(from, to)
Upvotes: 0