Last active
February 4, 2022 21:58
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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