#android #kotlin #android-viewmodel #android-mvvm
#Android #kotlin #android-viewmodel #android-mvvm
Вопрос:
- Я пытаюсь следовать шаблону MVVM в своем приложении для Android, но получаю ошибку при создании экземпляра ViewModel.
- Ошибка:
Cannot create an instance of class DemoViewModel class
.
Вот мой код:
DemoFragment.kt:
class DemoFragment : Fragment(R.layout.fragment_demo) {
lateinit var mViewModel: DemoViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewModel=ViewModelProvider(this).get(DemoViewModel::class.java)
mViewModel.getSomeData()
}
}
DemoViewModel.kt:
class DemoViewModel(val demoRepository: DemoRepository) : ViewModel() {
fun getSomeData() {
Log.d("DemoViewModel", "${demoRepository.getData()}")
}
}
DemoRepository.kt:
interface DemoRepository {
fun getData(): Boolean
}
class DemoImpl : DemoRepository {
override fun getData() = false
}
Ответ №1:
Вам нужно использовать ViewModelFactory. Потому что в вашем основном сборщике есть «demoRepository».
class DemoViewModelFactory constructor(private val repository:DemoImpl): ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return if (modelClass.isAssignableFrom(DemoViewModel::class.java!!)) {
DemoViewModel(this.repository) as T
} else {
throw IllegalArgumentException("ViewModel Not Found")
}
}
}
Использование
viewModel = ViewModelProvider(this, DemoViewModelFactory(repositoryObject)).get(DemoViewModel::class.java)
Комментарии:
1. Можете ли вы предоставить ответ с примером?
2. Но как я могу инициализировать DemoRepository для передачи в конструкторе DemoViewModelFactory?
3. репозиторий val = DemoRepository() 🙂
4. Но это интерфейс! У вас что-то есть?
5. Это приведено выше.
Ответ №2:
Я бы посоветовал вам использовать функцию расширения «by ViewModels ()», чтобы легко создать экземпляр ViewModel. Обратите внимание, что для его использования необходимо добавить следующую зависимость:
implementation 'androidx.fragment:fragment-ktx:1.2.5'
Пример реализации фрагмента:
class DemoFragment : Fragment() {
// Use the 'by ViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: DemoViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
// Update the UI
})
}
}
Затем вы можете внедрить экземпляр своего репозитория с помощью конструктора с помощью Dagger или Hilt и т. Д.
Комментарии:
1. Так что мне не придется использовать ViewModelFactory, когда в моем классе репозитория есть параметры или нет?
2. Вы должны внедрить свой репозиторий в свою ViewModel через его конструктор. Поначалу это может показаться необязательным, но это хорошая привычка, чтобы сделать ваш код хорошо организованным и тестируемым. Пожалуйста, найдите ниже пример, который я только что сделал с помощью HILT: github.com/bakikocak/Android-MVVM-Sample/blob/main/app/src/main /…
3. Идея в основном состоит в том, чтобы иметь пользовательский интерфейс (Activity, Fragment) настолько простым, насколько это возможно. Так что ваш фрагмент ничего не должен знать о репозитории. Он должен только наблюдать за изменениями в ViewModel и вносить изменения в пользовательский интерфейс.