После прочтения этого великого среднего из Elye я начинаю думать о том, как я справляюсь с ViewModels
(с шаблоном или без него). Обычно я собирался использовать подход Dagger Android, более подробный с фабриками Assisted Injected
ViewModels
и generic c, et c. Тем не менее, у меня была проблема .
Во всяком случае, во всем посте я узнал, что могу решить мою проблему, удалив Assisted Inject
logi c из моего ViewModels
и удалив зависимости, введенные конструктором. по моему ViewModelFactory
. С этим я решил проблему с пакетом, но - и очень большой, но ^^ - установка стала более многословной, так как теперь мне пришлось создавать фабрику для каждого ViewModel
- облома.
К счастью, автор показывает нам (меня интересуют только Dagger
решения), что мы можем фактически отбросить все фабричные логики c и использовать «Простое решение на основе кинжала» , где - проще говоря - мы перемещаем все конструктор вставил зависимости в инжекцию поля (да, они будут опубликованы c, это также вызывает у меня зуд, но оно превосходит весь шаблон, и вы можете сделать их protected
). SavedStateHandle
остается в конструкторе, а by viewModels()
приходит на помощь (в Activity
или Fragment
).
My BaseActivity :
abstract class BaseActivity<VM : ViewModel, ...> : ... {
@Inject
lateinit var viewModelFactory: ViewModelFactory
protected val viewModel: VM by lazy { ViewModelProvider(this, viewModelFactory).get(getViewModelClass()) }
protected abstract fun getViewModelClass(): Class<VM>
...
}
Я начал с попытки изменить это на:
protected val viewModel: VM by viewModels(getViewModelClass())
Но это не сработало, поэтому я скопировал viewModels()
и изменил его на:
private fun viewModels(
clazz: KClass<VM>,
factoryProducer: (() -> ViewModelProvider.Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(clazz, { viewModelStore }, factoryPromise)
}
protected val viewModel: VM by viewModels(getViewModelClass())
И это сработало! Но было выдано предупреждение ...:
Вызов не финальной функции в конструкторе.
Итак, я добавил это:
private fun initViewModel(): VM {
val v: VM by viewModels(getViewModelClass())
return v
}
protected val viewModel: VM by lazy { initViewModel() }
И наконец BaseActivity ViewModel
logi c стал:
abstract class BaseActivity<VM : ViewModel,...> : ... {
private fun viewModels(
clazz: KClass<VM>,
factoryProducer: (() -> ViewModelProvider.Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(clazz, { viewModelStore }, factoryPromise)
}
private fun initViewModel(): VM {
val v: VM by viewModels(getViewModelClass(), getViewModelFactory())
return v
}
protected val viewModel: VM by lazy { initViewModel() }
protected fun getViewModelFactory(): (() -> ViewModelProvider.Factory)? = null
...
}
Нет предупреждений, нет ошибок во время компиляции, нет ошибок во время выполнения - это работает!
Почему мои Activities
/ Fragments
не могут справиться со своими ViewModel
? Они могут, но:
abstract class BaseActivity<VM : ViewModel, ViewBinding : ViewDataBinding> ... {
...
protected val viewModel: VM by lazy { initViewModel() }
protected val binding: ViewBinding by lazy { DataBindingUtil.setContentView<ViewBinding>(this, getLayoutResId()) }
...
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
...
super.onCreate(savedInstanceState)
binding.lifecycleOwner = this
binding.setVariable(getViewModelVariableId(), viewModel)
...
initViews(binding, viewModel)
}
}
У меня есть такой лог установки c, и я не хочу его повторять.
Итак, что вы думаете об этом, полезном или чрезмерном проектировании? Буду ли я столкнуться с неприятностями?