Skip to content

Instantly share code, notes, and snippets.

@hi-manshu
Created July 7, 2021 05:54
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 hi-manshu/75c5bfdfd2d3a921fe63877dd032da26 to your computer and use it in GitHub Desktop.
Save hi-manshu/75c5bfdfd2d3a921fe63877dd032da26 to your computer and use it in GitHub Desktop.
abstract class BaseAdapter<T : Any, VH : BaseItemViewHolder<T, out BaseItemViewModel<T>>>(
parentLifecycle: Lifecycle,
private val dataList: ArrayList<T>
) : RecyclerView.Adapter<VH>() {
private var recyclerView: RecyclerView? = null
init {
parentLifecycle.addObserver(object : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onParentDestroy() {
recyclerView?.run {
for (i in 0 until childCount) {
getChildAt(i)?.let {
(getChildViewHolder(it) as BaseItemViewHolder<*, *>)
.run {
onDestroy()
viewModel.onManualCleared()
}
}
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onParentStop() {
recyclerView?.run {
for (i in 0 until childCount) {
getChildAt(i)?.let {
(getChildViewHolder(it) as BaseItemViewHolder<*, *>).onStop()
}
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onParentStart() {
recyclerView?.run {
if (layoutManager is LinearLayoutManager) {
val first = (layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
val last = (layoutManager as LinearLayoutManager).findLastVisibleItemPosition()
if (first in 0..last)
for (i in first..last) {
findViewHolderForAdapterPosition(i)?.let {
(it as BaseItemViewHolder<*, *>).onStart()
}
}
}
}
}
})
}
override fun onViewAttachedToWindow(holder: VH) {
super.onViewAttachedToWindow(holder)
holder.onStart()
}
override fun onViewDetachedFromWindow(holder: VH) {
super.onViewDetachedFromWindow(holder)
holder.onStop()
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
this.recyclerView = recyclerView
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
this.recyclerView = null
}
override fun getItemCount(): Int = dataList.size
override fun onBindViewHolder(holder: VH, position: Int) {
holder.bind(dataList[position])
}
fun appendData(dataList: List<T>) {
val oldCount = itemCount
this.dataList.addAll(dataList)
val currentCount = itemCount
if (oldCount == 0 && currentCount > 0)
notifyDataSetChanged()
else if (oldCount > 0 && currentCount > oldCount)
notifyItemRangeChanged(oldCount - 1, currentCount - oldCount)
}
fun updateList(list: List<T>) {
dataList.clear()
dataList.addAll(list)
notifyDataSetChanged()
}
}
abstract class BaseItemViewHolder<T : Any, VM : BaseItemViewModel<T>>(
@LayoutRes layoutId: Int, parent: ViewGroup
) : RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(layoutId, parent, false)),
LifecycleOwner {
init {
onCreate()
}
@Inject
lateinit var viewModel: VM
@Inject
lateinit var lifecycleRegistry: LifecycleRegistry
override fun getLifecycle(): Lifecycle = lifecycleRegistry
open fun bind(data: T) {
viewModel.updateData(data)
}
protected fun onCreate() {
injectDependencies(buildViewHolderComponent())
lifecycleRegistry.markState(Lifecycle.State.INITIALIZED)
lifecycleRegistry.markState(Lifecycle.State.CREATED)
setupObservers()
setupView(itemView)
}
fun onStart() {
lifecycleRegistry.markState(Lifecycle.State.STARTED)
lifecycleRegistry.markState(Lifecycle.State.RESUMED)
}
fun onStop() {
lifecycleRegistry.markState(Lifecycle.State.STARTED)
lifecycleRegistry.markState(Lifecycle.State.CREATED)
}
fun onDestroy() {
lifecycleRegistry.markState(Lifecycle.State.DESTROYED)
}
private fun buildViewHolderComponent() =
DaggerViewHolderComponent
.builder()
.applicationComponent((itemView.context.applicationContext as Application).applicationComponent)
.viewHolderModule(ViewHolderModule(this))
.build()
fun showMessage(message: String) = Toaster.show(itemView.context, message)
fun showMessage(@StringRes resId: Int) = showMessage(itemView.context.getString(resId))
protected open fun setupObservers() {
viewModel.messageString.observe(this, Observer {
it.data?.run { showMessage(this) }
})
viewModel.messageStringId.observe(this, Observer {
it.data?.run { showMessage(this) }
})
}
protected abstract fun injectDependencies(viewHolderComponent: ViewHolderComponent)
abstract fun setupView(view: View)
}
abstract class BaseItemViewModel<T : Any>(
schedulerProvider: SchedulerProvider,
compositeDisposable: CompositeDisposable,
networkHelper: NetworkHelper
) : BaseViewModel(schedulerProvider, compositeDisposable, networkHelper) {
val data: MutableLiveData<T> = MutableLiveData()
fun onManualCleared() = onCleared()
fun updateData(data: T) {
this.data.postValue(data)
}
}
@Module
class ViewHolderModule(private val viewHolder: BaseItemViewHolder<*, *>) {
@Provides
@ViewModelScope
fun provideLifecycleRegistry(): LifecycleRegistry = LifecycleRegistry(viewHolder)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment