Skip to content

Instantly share code, notes, and snippets.

@MazyNoc
Last active February 4, 2022 21:58
Show Gist options
  • Save MazyNoc/81da09db2e098745e2fc416c3db9956f to your computer and use it in GitHub Desktop.
Save MazyNoc/81da09db2e098745e2fc416c3db9956f to your computer and use it in GitHub Desktop.
A RecyclerView adapter that respects both the RecyclerViews attach and detach view, and an external LifecycleOwner.
import android.util.Log
import android.view.View
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.recyclerview.widget.RecyclerView
import app.BuildConfig
abstract class LifecycleAwareAdapter<T : LifecycleAwareAdapter.ViewHolder>(private val lifecycleOwner: LifecycleOwner) : RecyclerView.Adapter<T>(), DefaultLifecycleObserver {
companion object {
var DEBUG = BuildConfig.DEBUG
}
override fun onBindViewHolder(holder: T, position: Int) {
holder.lifecycleOwner = lifecycleOwner
holder.bound()
}
override fun onViewAttachedToWindow(holder: T) {
super.onViewAttachedToWindow(holder)
holder.attached()
}
override fun onViewDetachedFromWindow(holder: T) {
super.onViewDetachedFromWindow(holder)
holder.detached()
}
override fun onViewRecycled(holder: T) {
super.onViewRecycled(holder)
holder.recycled()
}
open class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), DefaultLifecycleObserver, LifecycleOwner {
@Suppress("LeakingThis")
private val lifecycleRegistry = LifecycleRegistry(this)
companion object {
const val TAG = "viewholder"
}
override fun getLifecycle(): LifecycleRegistry {
if (lifecycleOwner == null) throw IllegalStateException("Must bind before observing lifecycle events")
return lifecycleRegistry
}
var lifecycleOwner: LifecycleOwner? = null
set(value) {
if (field == value) return
if (DEBUG) Log.d(TAG, "set lifecycleOwner called")
field?.lifecycle?.removeObserver(this)
field = value
field?.lifecycle?.addObserver(this)
}
private fun safeSetState(state: Lifecycle.State) {
try {
lifecycleRegistry.currentState = state
} catch (e: IllegalStateException) {
if (DEBUG) Log.e(TAG, "Error changing state", e)
}
}
private var internalState = Lifecycle.State.CREATED
set(value) {
field = value
if (parentState.isAtLeast(value)) {
if (DEBUG) Log.d(TAG, "currentState ${value.name}")
safeSetState(value)
}
}
private var parentState = Lifecycle.State.INITIALIZED
set(value) {
field = value
if (internalState.isAtLeast(value)) {
if (DEBUG) Log.d(TAG, "currentState ${value.name}")
safeSetState(value)
}
}
override fun onCreate(owner: LifecycleOwner) {
if (DEBUG) Log.d(TAG, "onCreate() called with: owner = $owner")
parentState = Lifecycle.State.CREATED
}
override fun onStart(owner: LifecycleOwner) {
if (DEBUG) Log.d(TAG, "onStart() called with: owner = $owner")
parentState = Lifecycle.State.STARTED
}
override fun onResume(owner: LifecycleOwner) {
if (DEBUG) Log.d(TAG, "onResume() called with: owner = $owner")
parentState = Lifecycle.State.RESUMED
}
override fun onPause(owner: LifecycleOwner) {
if (DEBUG) Log.d(TAG, "onPause() called with: owner = $owner")
parentState = Lifecycle.State.STARTED
}
override fun onStop(owner: LifecycleOwner) {
if (DEBUG) Log.d(TAG, "onStop() called with: owner = $owner")
parentState = Lifecycle.State.CREATED
}
override fun onDestroy(owner: LifecycleOwner) {
if (DEBUG) Log.d(TAG, "onDestroy() called with: owner = $owner")
parentState = Lifecycle.State.DESTROYED
}
fun bound() {
if (DEBUG) Log.d(TAG, "bound() called")
if (internalState <= Lifecycle.State.CREATED) {
internalState = Lifecycle.State.CREATED
}
}
fun attached() {
if (DEBUG) Log.d(TAG, "attached() called")
internalState = Lifecycle.State.RESUMED
}
fun detached() {
if (DEBUG) Log.d(TAG, "detached() called")
internalState = Lifecycle.State.CREATED
}
fun recycled() {
if (DEBUG) Log.d(TAG, "recycled() called")
internalState = Lifecycle.State.DESTROYED
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment