Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save dmytroIncloud/31e76f688617f2836d5ee1b52fbc672a to your computer and use it in GitHub Desktop.
Save dmytroIncloud/31e76f688617f2836d5ee1b52fbc672a to your computer and use it in GitHub Desktop.
AsyncListDiffer
import android.support.v7.recyclerview.extensions.AsyncListDiffer
import android.support.v7.util.DiffUtil
import android.support.v7.widget.RecyclerView
import com.example.dimi.reactiveclean.extensions.paginator.PaginatorModelData
import com.example.dimi.reactiveclean.models.RecyclerUpdate
import com.example.dimi.reactiveclean.models.content.ContentDisplayable
import com.example.dimi.reactiveclean.models.content.ContentState
import com.example.dimi.reactiveclean.utils.DiffUtilCallbackContent
import com.example.dimi.reactiveclean.utils.DiffUtilContent
import com.example.dimi.reactiveclean.utils.SchedulersProvider
import com.hannesdorfmann.adapterdelegates3.ListDelegationAdapter
import io.reactivex.Single
import io.reactivex.disposables.Disposable
import timber.log.Timber
class NewsMainContentAdapter(
private val loadNextPage: () -> Unit,
val openCurrentContent: (ContentDisplayable.Content) -> Unit,
private val schedulers: SchedulersProvider
) : ListDelegationAdapter<MutableList<ContentDisplayable>>() {
private var disposable: Disposable? = null
private val asyncListDiffer: AsyncListDiffer<ContentDisplayable> =
AsyncListDiffer(this, DiffUtilCallbackContent())
init {
items = mutableListOf()
delegatesManager.addDelegate(NewsMainContentDisplayableAdapter(openCurrentContent))
.addDelegate(ProgressAdapter())
.addDelegate(ErrorAdapter(loadNextPage))
.setFallbackDelegate(AllDataAdapter())
}
override fun onBindViewHolder(
holder: RecyclerView.ViewHolder,
position: Int,
payloads: MutableList<Any?>
) {
super.onBindViewHolder(holder, position, payloads)
if (position == items.size - DELTA_POSITION_LOADING && isContent()) loadNextPage.invoke()
}
fun setNewData(model: PaginatorModelData<ContentDisplayable>) {
disposable?.dispose()
val newList: MutableList<ContentDisplayable> = mutableListOf()
newList.addAll(model.content)
when (model.state) {
ContentState.DATA -> {
}
ContentState.PROGRESS -> newList.add(ContentDisplayable.Progress())
ContentState.ERROR -> newList.add(ContentDisplayable.Error())
ContentState.ALL_DATA -> newList.add(ContentDisplayable.AllContent())
}
when (model.recyclerUpdate) {
RecyclerUpdate.DIFF_UTIL -> disposable = notifyDiffUtil(newList)
RecyclerUpdate.NOTIFY -> notifyRanges(newList)
RecyclerUpdate.DIFF_UTIL_ITEM_CALLBACK -> notifyDiffUtilCallback(newList)
}
}
fun disposeSubscription() {
disposable?.dispose()
}
private fun isContent() = items.last() is ContentDisplayable.Content
private fun notifyDiffUtil(newList: List<ContentDisplayable>): Disposable {
return Single.fromCallable { DiffUtil.calculateDiff(DiffUtilContent(items, newList)) }
.compose(::composeSchedulers)
.subscribe(
{
items.apply { clear() }.addAll(newList)
it.dispatchUpdatesTo(this@NewsMainContentAdapter)
},
{ throw Exception(it.message) }
)
}
private fun notifyRanges(newList: List<ContentDisplayable>) {
items.apply { clear() }.addAll(newList)
notifyDataSetChanged()
}
private fun notifyDiffUtilCallback(newList: List<ContentDisplayable>) {
items.apply {
clear()
addAll(newList)
}
asyncListDiffer.submitList(newList)
}
private fun composeSchedulers(single: Single<DiffUtil.DiffResult>): Single<DiffUtil.DiffResult> =
single.subscribeOn(schedulers.computation())
.observeOn(schedulers.ui())
companion object {
const val DELTA_POSITION_LOADING = 5
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment