Skip to content

Instantly share code, notes, and snippets.

@kakajika
Created September 13, 2021 09:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kakajika/7020951106a21753ea64df743e54b2e6 to your computer and use it in GitHub Desktop.
Save kakajika/7020951106a21753ea64df743e54b2e6 to your computer and use it in GitHub Desktop.
Concat multiple androidx.leanback.widget.ObjectAdapter like androidx.recyclerview.widget.ConcatAdapter
class ConcatObjectAdapter(
private vararg val adapters: ObjectAdapter
) : ObjectAdapter() {
init {
adapters.forEach { adapter ->
adapter.registerObserver(object : DataObserver() {
override fun onChanged() {
super.onChanged()
this@ConcatObjectAdapter.notifyChanged()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
super.onItemRangeChanged(positionStart, itemCount)
val offset = countItemsBefore(adapter)
this@ConcatObjectAdapter.notifyItemRangeChanged(
positionStart + offset,
itemCount
)
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
super.onItemRangeChanged(positionStart, itemCount, payload)
val offset = countItemsBefore(adapter)
this@ConcatObjectAdapter.notifyItemRangeChanged(
positionStart + offset,
itemCount,
payload
)
}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
super.onItemRangeInserted(positionStart, itemCount)
val offset = countItemsBefore(adapter)
this@ConcatObjectAdapter.notifyItemRangeInserted(
positionStart + offset,
itemCount
)
}
override fun onItemMoved(fromPosition: Int, toPosition: Int) {
super.onItemMoved(fromPosition, toPosition)
val offset = countItemsBefore(adapter)
this@ConcatObjectAdapter.notifyItemMoved(
fromPosition + offset,
toPosition + offset
)
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
super.onItemRangeRemoved(positionStart, itemCount)
val offset = countItemsBefore(adapter)
this@ConcatObjectAdapter.notifyItemRangeRemoved(
positionStart + offset,
itemCount
)
}
})
}
presenterSelector = object : PresenterSelector() {
override fun getPresenter(item: Any): Presenter {
return adapters.firstNotNullOf {
if (it.hasItemOfType(item::class.java)) {
try { it.getPresenter(item)
} catch (e: Exception) { null }
} else {
null
}
}
}
override fun getPresenters(): Array<Presenter> {
return adapters
.flatMap { it.presenterSelector.presenters.asList() }
.toTypedArray()
}
}
}
fun dispose() {
adapters.forEach { it.unregisterAllObservers() }
}
override fun size(): Int {
return adapters.sumOf { it.size() }
}
override fun get(position: Int): Any {
return resolveAdapterIndex(position)
?.let { (adapter, index) -> adapter.get(index) }
?: throw IllegalStateException()
}
override fun getId(position: Int): Long {
return resolveAdapterIndex(position)
?.let { (adapter, index) -> adapter.getId(index) }
?: throw IllegalStateException()
}
private fun countItemsBefore(adapter: ObjectAdapter): Int {
return adapters
.takeWhile { it !== adapter }
.sumOf { it.size() }
}
private fun resolveAdapterIndex(globalIndex: Int): Pair<ObjectAdapter, Int>? {
var offset: Int = 0
for (adapter in adapters) {
if (globalIndex in offset until offset+adapter.size()) {
return Pair(adapter, globalIndex - offset)
}
offset += adapter.size()
}
return null
}
private fun <T> ObjectAdapter.hasItemOfType(clazz: Class<T>): Boolean {
for (i in 0 until size()) {
if (clazz.isInstance(get(i))) return true
}
return false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment