Skip to content

Instantly share code, notes, and snippets.

@IMoHaMeDHaMdYI
Last active March 13, 2019 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IMoHaMeDHaMdYI/e977d8ab516dab622e5c832dd94a917a to your computer and use it in GitHub Desktop.
Save IMoHaMeDHaMdYI/e977d8ab516dab622e5c832dd94a917a to your computer and use it in GitHub Desktop.
BaseAdapter is a RecyclerView adapter that contains the main operations happen within the adapter,
interface Displayable {
fun getType(): Int
}
// ----------------------------------
abstract class ViewRenderer<in D : Displayable, VH : RecyclerView.ViewHolder>(val type: Int) {
abstract fun bindView(model: D, holder: VH)
abstract fun createViewHolder(parent: ViewGroup): VH
}
// ----------------------------------
abstract class BaseAdapter(private val context: Context, private val dataList: ArrayList<Displayable>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val STATE_START = 0
// This is used when the list is all empty.
private val STATE_LOADING_START = 1
// This is used when there is scroll to load more.
private val STATE_LOADING = 2
private val STATE_NETWORK_ERROR = 3
private val STATE_EMPTY = 4
// When true indicates that there is no previous error, loading, or empty states.
private var mReady = false
private val mRendererList = SparseArray<ViewRenderer<Displayable, RecyclerView.ViewHolder>>()
private val mState = BehaviorSubject.create<Int>().apply {
onNext(STATE_LOADING)
}
private val compositeDisplayable = CompositeDisposable()
init {
// TODO see if it actually needs to be reactive because I feel like this is overkilling it
compositeDisplayable.add(mState.observeOn(AndroidSchedulers.mainThread())
.subscribe {
when (mState.value) {
STATE_START -> onLoaded()
STATE_LOADING, STATE_LOADING_START -> onLoading()
STATE_EMPTY -> onEmpty()
STATE_NETWORK_ERROR -> onNetworkError()
}
}
)
}
fun setState(state: Int) {
if (state != STATE_START) mReady = false
mState.onNext(state)
}
private fun onLoading() {
dataList.add(object : Displayable {
override fun getType(): Int {
return if (dataList.size == 0) STATE_LOADING_START
else STATE_LOADING
}
})
}
private fun onNetworkError() {
dataList.add(object : Displayable {
override fun getType(): Int {
return STATE_NETWORK_ERROR
}
})
}
private fun onEmpty() {
dataList.add(object : Displayable {
override fun getType(): Int {
return STATE_EMPTY
}
})
}
private fun onLoaded() {
if (!mReady) dataList.removeAt(dataList.size - 1)
mReady = true
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val viewRenderer = mRendererList.get(viewType)
viewRenderer?.let { return it.createViewHolder(parent) }
throw RuntimeException("Not Supported Item View Type: $viewType")
}
fun registerRenderer(renderer: ViewRenderer<Displayable, RecyclerView.ViewHolder>) {
val type = renderer.type
if (mRendererList.get(type) == null) {
mRendererList.put(type, renderer)
}
}
override fun getItemCount(): Int {
return dataList.size
}
fun replace(list: ArrayList<Displayable>) {
dataList.clear()
dataList.addAll(list)
notifyDataSetChanged()
}
fun add(item: Displayable) {
dataList.add(item)
notifyItemInserted(dataList.size - 1)
}
fun add(itemList: ArrayList<Displayable>) {
val oldSz = itemList.size
dataList.addAll(itemList)
notifyItemRangeInserted(oldSz, itemList.size)
}
// Must be called in the lifecycle destroyer function.
fun onDestroy() {
compositeDisplayable.dispose()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment