This gist snippet is Public Domain.
-
-
Save keima/1b8cda30aec8cd50fec7743d2ccfa777 to your computer and use it in GitHub Desktop.
import android.os.Bundle | |
import android.util.Log | |
import android.view.ViewGroup | |
import android.widget.TextView | |
import androidx.appcompat.app.AppCompatActivity | |
import androidx.databinding.DataBindingUtil | |
import androidx.lifecycle.Lifecycle | |
import androidx.lifecycle.LifecycleObserver | |
import androidx.lifecycle.OnLifecycleEvent | |
import app.keima.android.recyclerviewsandbox.databinding.ActivityMainBinding | |
class MainActivity : AppCompatActivity() { | |
private lateinit var binding: ActivityMainBinding | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
binding = DataBindingUtil.setContentView(this, R.layout.activity_main) | |
binding.recyclerView.apply { | |
adapter = MyAdapter( | |
arrayOf( | |
"A", "B", "C", "D", | |
"A", "B", "C", "D", | |
"A", "B", "C", "D", | |
"A", "B", "C", "D" | |
) | |
) | |
} | |
} | |
} | |
class MyAdapter(private val dataset: Array<String>) : | |
LifecycleRecyclerAdapter<MyAdapter.MyViewHolder>() { | |
class MyViewHolder(private val textView: TextView) : LifecycleViewHolder(textView) { | |
private val observer = MyObserver() | |
init { | |
lifecycle.addObserver(observer) | |
} | |
fun bindData(data: String) { | |
textView.text = data | |
observer.data = data | |
} | |
} | |
class MyObserver() : LifecycleObserver { | |
var data: String = "?" | |
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE) | |
fun onCreate() { | |
Log.d("MyObserver", "appear: $data") | |
} | |
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) | |
fun onDestroy() { | |
Log.d("MyObserver", "disappear: $data") | |
} | |
} | |
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { | |
return MyViewHolder(TextView(parent.context).apply { | |
setPadding(8, 40, 8, 40) | |
}) | |
} | |
override fun onBindViewHolder(holder: MyViewHolder, position: Int) { | |
holder.bindData("${dataset[position]} $position") | |
} | |
override fun getItemCount() = dataset.size | |
} |
import androidx.recyclerview.widget.RecyclerView | |
abstract class LifecycleRecyclerAdapter<T : LifecycleViewHolder> : RecyclerView.Adapter<T>() { | |
override fun onViewAttachedToWindow(holder: T) { | |
super.onViewAttachedToWindow(holder) | |
holder.onAppear() | |
} | |
override fun onViewDetachedFromWindow(holder: T) { | |
super.onViewDetachedFromWindow(holder) | |
holder.onDisappear() | |
} | |
} |
import android.view.View | |
import androidx.lifecycle.Lifecycle | |
import androidx.lifecycle.LifecycleOwner | |
import androidx.lifecycle.LifecycleRegistry | |
import androidx.recyclerview.widget.RecyclerView | |
abstract class LifecycleViewHolder(itemView: View) : | |
RecyclerView.ViewHolder(itemView), LifecycleOwner { | |
private val lifecycleRegistry = LifecycleRegistry(this) | |
init { | |
lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED | |
} | |
fun onAppear() { | |
lifecycleRegistry.currentState = Lifecycle.State.CREATED | |
} | |
fun onDisappear() { | |
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED | |
} | |
override fun getLifecycle(): Lifecycle { | |
return lifecycleRegistry | |
} | |
} |
Hi I try this。 But if you destroyed the lifecycleRegister , the reuse viewholder's lifcyclRegistery will never send event to liveData anymore. It will lose some status. What can i do fix it? Help thanks
Hi I try this。 But if you destroyed the lifecycleRegister , the reuse viewholder's lifcyclRegistery will never send event to liveData anymore. It will lose some status. What can i do fix it? Help thanks
init {
lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
lifecycleRegistry.currentState = Lifecycle.State.CREATED
}
fun onAppear() {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
lifecycleRegistry.currentState = Lifecycle.State.RESUMED
}
fun onDisappear() {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
lifecycleRegistry.currentState = Lifecycle.State.CREATED
}
fun Destroy()
{
lifecycleRegistry.currentState = Lifecycle.State. DESTROYED
}
ans call this destroy method when you are going out of screen means this method should be observed from parent lifecycle(recyclerview lifecycle), so when you are changing the screen or exiting from app.
Hi I try this。 But if you destroyed the lifecycleRegister , the reuse viewholder's lifcyclRegistery will never send event to liveData anymore. It will lose some status. What can i do fix it? Help thanks
init {
lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
lifecycleRegistry.currentState = Lifecycle.State.CREATED
}fun onAppear() { lifecycleRegistry.currentState = Lifecycle.State.STARTED lifecycleRegistry.currentState = Lifecycle.State.RESUMED } fun onDisappear() { lifecycleRegistry.currentState = Lifecycle.State.STARTED lifecycleRegistry.currentState = Lifecycle.State.CREATED }
fun Destroy()
{
lifecycleRegistry.currentState = Lifecycle.State. DESTROYED
}ans call this destroy method when you are going out of screen means this method should be observed from parent lifecycle(recyclerview lifecycle), so when you are changing the screen or exiting from app.
Hi @abhinavjiit, I am trying to implement this. Would you mind giving us a light about how to properly call that destroy() method? I am out of ideas on how to do it...
Also asked on SO: https://stackoverflow.com/questions/68829954/how-to-implement-lifecycleowner-on-a-recycleradapter-viewholder
i have replied you in stack overflow as well
@jonathands, this is my repo you can see there https://github.com/abhinavjiit/baseRecyclerview/blob/master/app/src/main/java/com/example/pristencare/adapter/RecyclerViewImageAdapter.kt
Amazing! I will have a look at it now, try to implement and run Leakcanary! Thanks a lot!!
@jonathansds, this is my repo you can see there https://github.com/abhinavjiit/baseRecyclerview/blob/master/app/src/main/java/com/example/pristencare/adapter/RecyclerViewImageAdapter.kt
Amazing! I will have a look at it now, try to implement and run Leakcanary! Thanks a lot!!
if you got something wrong or any memory leak, plz let me know as well
@jonathands, this is my repo you can see there https://github.com/abhinavjiit/baseRecyclerview/blob/master/app/src/main/java/com/example/pristencare/adapter/RecyclerViewImageAdapter.kt
Amazing! I will have a look at it now, try to implement and run Leakcanary! Thanks a lot!!
if you got something wrong or any memory leak, plz let me know as well
Sure! I am implementing it now. Might take a lil bit because I want to fully understand the logic behind it but I should be able to fully test it today :)
@jonathands, this is my repo you can see there https://github.com/abhinavjiit/baseRecyclerview/blob/master/app/src/main/java/com/example/pristencare/adapter/RecyclerViewImageAdapter.kt
could you fix your mention so I don't get the notifications?
@abhinavjiit It's working like a charm! No memory leaks, no excess of objects allocated... It's just perfectly working! Well done!
@abhinavjiit It's working like a charm! No memory leaks, no excess of objects allocated... It's just perfectly working! Well done!
@jonathansds Cool bro.
@abhinavjiit
Hi! - I think there is possibly something wrong: RecyclerView.getChildCount
and RecyclerView.getChildAt
only return visible items.
My implementation
class SimpleLifeCycleOwnerImpl : SimpleLifeCycleOwner {
private var lifecycleRegistry: LifecycleRegistry? = null
override fun getLifecycle() =
lifecycleRegistry ?: run {
initialize()
lifecycleRegistry!!
}
override fun initialize() {
// The object can be revived, create a new lifecycle
lifecycleRegistry?.run {
if (currentState != Lifecycle.State.DESTROYED)
throw IllegalStateException("can be revived only after destroyed, get $currentState")
}
lifecycleRegistry = LifecycleRegistry(this)
}
override fun handleLifecycleEvent(event: Lifecycle.Event) {
lifecycleRegistry!!.handleLifecycleEvent(event)
}
}
// kotlin cannot inherit from type parameter like C++, we must use this class as base
// otherwise we need to copy the code for each adapter
abstract class LifecycleAdapter<VH : RecyclerView.ViewHolder>(lifecycleOwner: LifecycleOwner) :
RecyclerView.Adapter<VH>() {
private var recyclerView: RecyclerView? = null
init {
val observer = object : LifecycleEventObserver {
private fun visibleChildApply(block: SimpleLifeCycleOwner.() -> Unit) =
recyclerView?.run {
for (i in 0 until childCount)
getChildAt(i)?.let {
(getChildViewHolder(it) as? SimpleLifeCycleOwner)?.block()
}
} ?: Unit
private fun allChildApply(block: SimpleLifeCycleOwner.() -> Unit) =
recyclerView?.run {
for (i in 0 until itemCount)
(findViewHolderForAdapterPosition(i) as? SimpleLifeCycleOwner)?.block()
} ?: Unit
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) =
when (event) {
Lifecycle.Event.ON_DESTROY -> allChildApply { handleLifecycleEvent(event) }
else -> visibleChildApply { handleLifecycleEvent(event) }
}
}
lifecycleOwner.lifecycle.addObserver(observer)
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
if (this.recyclerView != null)
throw IllegalStateException("can be attached to only one RecyclerView")
this.recyclerView = recyclerView
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
throw IllegalStateException("must not be detached")
}
override fun onViewAttachedToWindow(holder: VH) =
(holder as? SimpleLifeCycleOwner)?.run {
handleLifecycleEvent(Lifecycle.Event.ON_START)
handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
} ?: Unit
override fun onViewDetachedFromWindow(holder: VH) =
(holder as? SimpleLifeCycleOwner)?.run {
handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
handleLifecycleEvent(Lifecycle.Event.ON_STOP)
} ?: Unit
override fun onBindViewHolder(holder: VH, position: Int) =
(holder as? SimpleLifeCycleOwner)?.run {
initialize()
handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
// logical views are created here
} :? Unit
override fun onViewRecycled(holder: VH) =
(holder as? SimpleLifeCycleOwner)?.run {
handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
} ?: Unit
}
It will cause memory leak, when RecyclerView detach from window, the onViewDetachedFromWindow callback will not invoked.
2019/10/24 Updated.