Skip to content

Instantly share code, notes, and snippets.

@4xes
Last active June 26, 2020 13:31
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 4xes/3d69bfdcf8093bfdad02229d98e4fed2 to your computer and use it in GitHub Desktop.
Save 4xes/3d69bfdcf8093bfdad02229d98e4fed2 to your computer and use it in GitHub Desktop.
Empty state cursor recycler adapter
package com.efectum.ui.base.adapter
import android.util.Log
import android.database.Cursor
import android.database.DataSetObserver
import androidx.recyclerview.widget.RecyclerView
abstract class CursorAdapter<VH : RecyclerView.ViewHolder>(cursor: Cursor?) : RecyclerView.Adapter<VH>() {
var cursor: Cursor? = null
private set
protected var dataValid: Boolean = false
private var rowIdColumn: Int = 0
private val dataSetObserver: DataSetObserver?
init {
this.cursor = cursor
dataValid = cursor != null
rowIdColumn = if (dataValid) this.cursor!!.getColumnIndex("_id") else -1
dataSetObserver = NotifyingDataSetObserver()
if (this.cursor != null) {
this.cursor!!.registerDataSetObserver(dataSetObserver)
}
}
override fun getItemCount(): Int {
if (dataValid) {
return cursor?.count ?: 0
}
return 0
}
override fun getItemId(position: Int): Long {
if (dataValid && cursor != null && cursor!!.moveToPosition(position)) {
return cursor!!.getLong(rowIdColumn)
}
return 0
}
override fun setHasStableIds(hasStableIds: Boolean) {
super.setHasStableIds(true)
}
abstract fun onBindViewHolder(viewHolder: VH, cursor: Cursor)
override fun onBindViewHolder(viewHolder: VH, position: Int) {
if (moveCursorToPosition(position)) {
onBindViewHolder(viewHolder, cursor!!)
}
}
protected fun moveCursorToPosition(position: Int): Boolean {
if (!dataValid) {
Log.e("Error", "this should only be called when the cursor is valid")
return false
}
if (!cursor!!.moveToPosition(position)) {
Log.e("Error", "couldn't move cursor to position $position")
return false
}
return true
}
/**
* Change the underlying cursor to a new cursor. If there is an existing cursor it will be
* closed.
*/
fun changeCursor(cursor: Cursor) {
swapCursor(cursor)?.close()
}
/**
* Swap in a new Cursor, returning the old Cursor. Unlike
* [.changeCursor], the returned old Cursor is *not*
* closed.
*/
private fun swapCursor(newCursor: Cursor): Cursor? {
if (newCursor === cursor) {
return null
}
val oldCursor = cursor
if (dataSetObserver != null) {
oldCursor?.unregisterDataSetObserver(dataSetObserver)
}
cursor = newCursor
if (cursor != null) {
if (dataSetObserver != null) {
cursor!!.registerDataSetObserver(dataSetObserver)
}
rowIdColumn = newCursor.getColumnIndexOrThrow("_id")
dataValid = true
notifyDataSetChanged()
} else {
rowIdColumn = -1
dataValid = false
notifyDataSetChanged()
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
}
return oldCursor
}
private inner class NotifyingDataSetObserver : DataSetObserver() {
override fun onChanged() {
super.onChanged()
dataValid = true
notifyDataSetChanged()
}
override fun onInvalidated() {
super.onInvalidated()
dataValid = false
notifyDataSetChanged()
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
}
}
}
package com.efectum.ui.base.adapter
import android.database.Cursor
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
abstract class EmptySearchCursorAdapter<VH : RecyclerView.ViewHolder>(cursor: Cursor?) : CursorAdapter<RecyclerView.ViewHolder>(cursor) {
override fun getItemViewType(position: Int) = if (super.getItemCount() == 0) {
TYPE_EMPTY
} else {
TYPE_ITEM
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) {
TYPE_ITEM -> {
onCreateViewItemHolder(parent)
}
else -> {
onCreateViewEmptyHolder(parent)
}
}
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
TYPE_ITEM -> {
if (moveCursorToPosition(position)) {
@Suppress("UNCHECKED_CAST")
onBindViewItemHolder(viewHolder as VH, cursor!!)
}
}
}
}
open fun onCreateViewEmptyHolder(parent: ViewGroup): RecyclerView.ViewHolder {
return EmptyHolder(View(parent.context))
}
abstract fun onBindViewItemHolder(holder: VH, cursor: Cursor)
abstract fun onCreateViewItemHolder(parent: ViewGroup): VH
override fun getItemCount(): Int {
val itemCount = super.getItemCount()
if (itemCount == 0) {
return 1
}
return itemCount
}
class EmptyHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
companion object {
const val TYPE_EMPTY = 0
const val TYPE_ITEM = 1
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment