ViewModels не предназначены для использования с элементами RecyclerView
Почему?
ViewModel
- это AA C (Android Компонент архитектуры ) , единственная цель которого - пережить изменения конфигурации жизненного цикла Android Activity / Fragment , чтобы в таком случае данные можно было сохранить через ViewModel.
Вот почему это не должно не может быть использовано в RecyclerView (ViewHolder) Элементы, поскольку само представление элемента будет частью Activity / Fragment, и оно (RecyclerView / ViewHolder) не содержит никакого специального c API ViewModelStoreOwner
(из которого ViewModel в основном получены для данного экземпляра Activity / Fragment) .
Simplisti c синтаксис для получения ViewModel:
ViewModelProvider(this).get(ViewModel::class.java)
& here this
будет относиться к контексту действия / фрагмента.
Так что даже если вы в конечном итоге будете использовать ViewModel
в RecyclerView
Items, это даст вам тот же самый экземпляр из-за к контексту может быть активность / фрагмент одинаков на протяжении всей корзины rView, который не имеет смысла для меня. Таким образом, ViewModel бесполезен для RecyclerView или не сильно способствует этому делу.
TL; DR
Решение?
Вы можете напрямую передать LiveData
объект, который вам нужно наблюдать из вашей деятельности / фрагмента ViewModel
в вашем RecyclerView.Adapter
классе. Вам также понадобится предоставить LifecycleOwner
для адаптера, чтобы начать наблюдать эти данные в реальном времени.
Таким образом, ваш класс Adapter будет выглядеть примерно так:
class RecyclerViewAdapter(private val liveDataToObserve: LiveData<T>, private val lifecycleOwner: LifecycleOwner) : RecyclerView.Adapter<ViewHolder>() {
init {
liveDataToObserve.observe(lifecycleOwner) { t ->
// Notify data set or something...
}
}
}
Если это это не так, и вы хотите, чтобы он был в классе ViewHolder
, тогда вы можете передать объект LiveData
во время метода onCreateViewHolder
в свой экземпляр ViewHolder вместе с lifecycleOwner
.
Бонус!
Если вы используете привязку данных к элементам RecyclerView, вы можете легко получить объект lifecyclerOwner
из своего класса привязки. Все, что вам нужно сделать, это установить его во время onCreateViewHolder()
, как показано ниже:
class RecyclerViewAdapter(private val liveDataToObserve: LiveData<T>, private val lifecycleOwner: LifecycleOwner) : RecyclerView.Adapter<ViewHolder>() {
override fun onCreateViewHolder: ViewHolder {
// Some piece of code for binding
binding.lifecycleOwner = this@RecyclerViewAdapter.lifecycleOwner
// Another piece of code and return viewholder
}
}
class ViewHolder(private val someLiveData: LiveData<T>, binding: ViewDataBinding): RecyclerView.ViewHolder(binding.root) {
init {
someLiveData.observe(requireNotNull(binding.lifecycleOwner)) { t->
// set your UI by live data changes here
}
}
}
Так что да, вы можете использовать класс-оболочку для ваших ViewHolder
экземпляров, чтобы предоставить вам LiveData
из коробки, но Я бы не одобрял это, если класс-оболочка расширяет класс ViewModel
.
Как только вы захотите имитировать onCleared()
метод ViewModel
, вы можете создать метод для вашего класса-оболочки, который будет вызываться при ViewHolder
перерабатывается или отсоединяется от окна методом onViewRecycled()
или onViewDetachedFromWindow()
в зависимости от того, что лучше всего подходит для вашего случая.
Редактировать для комментария @Mariusz: беспокойство по поводу использования Activity / Fragment как LifecycleOwner является правильным. Но было бы немного непонимание, считая это как PO C.
Как только кто-то использует lifecycleOwner
для наблюдения LiveData
в данном RecyclerViewHolder
элементе, это нормально, потому что LiveData
является компонентом, поддерживающим жизненный цикл, и он обрабатывает подписку на жизненный цикл внутри, поэтому безопасен в использовании. Даже если вы можете явно удалить наблюдение, если хотите, используя метод onViewRecycled()
или onViewDetachedFromWindow()
.
Об асинхронной c операции внутри ViewHolder
:
Если вы используете сопрограммы, то вы можете использовать lifecycleScope
из lifecycleOwner
для вызова вашей операции, а затем предоставить данные обратно конкретному наблюдению LiveData
без явной обработки случая очистки (LifecycleScope
позаботится об этом для вас) .
Если вы не используете Coroutines, вы все равно можете сделать свой вызов asy c и предоставить данные обратно для наблюдения LiveData
и не беспокоиться о том, чтобы очистить ваш Операция asyn c во время onViewRecycled()
или onViewDetachedFromWindow()
обратных вызовов. Здесь важно отметить LiveData
, который учитывает жизненный цикл данной LifecycleOwner
, а не текущую асинхронную c операцию.