Как использовать один ViewModelFactory для обеспечения всех ViewModels с Dagger

Как я могу реализовать универсальную фабрику ViewModel для обеспечения всех моделей ViewModel моего проекта? Чтобы было ясно, мои ViewModels имеют зависимости (как параметры конструктора)

5
0
3 798
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ну, есть один, который называется GithubБраузер, но это не учебник, а проект. Вы должны знать кинжал для Android, чтобы сделать это. Или вы можете проверить код ниже:

@Singleton
class DaggerViewModelFactory @Inject constructor(
    private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        val creator = creators[modelClass] ?: creators.entries.firstOrNull {
            modelClass.isAssignableFrom(it.key)
        }?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
        try {
            @Suppress("UNCHECKED_CAST")
            return creator.get() as T
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
}

Эта часть создаст «универсальную» модель представления для всего вашего приложения. Таким образом, ViewModel создается с назначенными аргументами. После этого вам нужно внедрить фабричный модуль в свои модули Singleton и включить его в компонент.

@Component(
    modules = [... ViewModelModule::class]
)
interface AppCompoenent{}

Теперь самое интересное:

    @Suppress("unused")
    @Module
    abstract class ViewModelModule {
        @Binds
        @IntoMap
        @ViewModelKey(MyViewModel::class)
        abstract fun bindsMyViewModel(viewModel: MyViewModel): ViewModel

    @Binds
    abstract fun bindsViewModelFactory(factory: DaggerViewModelFactory): ViewModelProvider.Factory
}

Поскольку кинжал поддерживает множественное связывание, вы можете связывать его сколько угодно ViewModels по своему усмотрению.

Ключ модели представления:

@Target(
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY_GETTER,
    AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)

Вы в основном помещаете значения в хэш-карту. Эти ценности — ваши ViewModel.

Хит строить! Готово. После этого вы просто вставляете ViewModelProvider.Facory в свой фрагмент. Чем в вашем ViewModel вы можете сделать:

class MyViewModel @Inject constructor(
    private val dependency: YourDependency
) : ViewModel() {}

Чтобы было понятно, что вы просили в комментариях. Во-первых, нет особой необходимости знать, что происходит внутри DaggerViewModelFactory, хотя я не рекомендую учиться таким образом, потому что я большой поклонник принципа «Всегда знать, что происходит». К вашему сведению, DaggerViewModelFactory — это просто класс, который принимает Map с каждым классом, который расширяет ViewModel в качестве ключа, и зависимости этого класса в качестве значения. При использовании Provider<T> Dagger знает, как найти эти зависимости, но еще не доводит их до вас, пока вы не вызовете provider.get(). Думайте об этом как о ленивой инициализации.

Теперь проверьте modelClass.isAssignableFrom(it.key). Он просто проверяет, действительно ли этот класс расширяется ViewModel.

Что касается вашего второго вопроса, важно понять первую часть. Поскольку Dagger поддерживает множественное связывание, это означает, что вы можете предоставлять зависимости с помощью Map<Key, Value>. Например, Map<HomeViewModel, Provider<ViewModel>> в основном скажет кинжалу, который даст мне зависимости HomeViewModel. Кинжал скажет: Как узнать, какие HomeViewModel зависимости? И вы отвечаете: я уже определил для этого ключ, и это сам класс HomeViewModel. Итак, вы просто создаете аннотацию, комбинируете ее с @Binds и @IntoMap, а на фоне Dagger просто выполняет map.put(HomeViewModel::class, AndDependencies).

Должен ли я знать, как сделать ModelViewFactory или достаточно скопировать-вставить?

David 24.07.2019 13:32

А VIewModelKey нужен? Я не знаю, что такое области действия Target и Retention. Может быть, это как модуль для отображения ViewModels?

David 24.07.2019 13:47

Не волнуйтесь, я добавлю в пост дополнительные исследования.

coroutineDispatcher 24.07.2019 14:01

сделано, пожалуйста, проверьте еще раз

coroutineDispatcher 24.07.2019 14:12

Большое спасибо! Ясно и легко понять!

David 24.07.2019 15:47

Рад, что помог :)

coroutineDispatcher 24.07.2019 15:48

Я только начинаю работать с Dagger в проекте, и мне трудно понять, многие вещи я просто копировал и вставлял, не зная, что они делают, вы порекомендуете мне какой-либо способ изучить это?

David 24.07.2019 15:50

Ну, это своего рода продвинутый, когда вы новичок. У меня есть собственная статья о кинжале, если вы хотите изучить основы: medium.com/@stavro96/keep-it-simple-with-dagger-2-241d32e14d‌​e

coroutineDispatcher 24.07.2019 15:58

Отлично, пойду проверю!

David 24.07.2019 16:01

Я видел ваш пример на Medium, но я не понимаю, как используются области действия, область с аннотацией Retention говорит только о том, что зависимость должна запускаться, когда приложение запущено, поэтому не имеет смысла или, по крайней мере, я не понимаю видеть это.

David 25.07.2019 09:50

Масштаб — это просто метка, ничего больше. Так же, как переопределение. это ничего не делает. Единственное, что он делает, это чтобы dagger знал уровень зависимости. Если вы проверите аннотацию @Singleton, вы найдете то же самое. Итак, масштабы определяют иерархию найма. Пожалуйста, посмотрите видео скрученного уравнения на прицелах для лучшего понимания.

coroutineDispatcher 25.07.2019 09:55

Где я могу найти это видео?

David 25.07.2019 09:59

В конце моей статьи у вас есть 3 ресурса для изучения кинжала. Откройте скрученные уравнения и перейдите к серии прицелов.

coroutineDispatcher 25.07.2019 10:00

извините, это название Dagger 2 Android Tutorial

coroutineDispatcher 25.07.2019 10:03

Я это вижу и теперь понимаю, еще раз спасибо!

David 25.07.2019 10:17

Но есть одна мысль, которую я не вижу ясно. Я знаю, для чего нужны области, но, например, область действия MapKey отображает мою активность, так что это не просто отметка о том, что я знаю уровень зависимости, нет?

David 25.07.2019 10:23

@MapKey по своему названию не выглядит размахом

coroutineDispatcher 25.07.2019 10:36

Последний вопрос, пожалуйста, чтобы закончить понимать все: Для чего нужен ViewModelProvider.Factory?

David 25.07.2019 11:01

Поскольку ViewModel имеет собственный жизненный цикл, вы не можете инициализировать ViewModel с помощью обычного конструктора, поэтому для него вам нужна фабрика.

coroutineDispatcher 25.07.2019 11:14

Я публикую новый вопрос, если вы можете помочь мне решить проблему @coroutineDispatcher stackoverflow.com/questions/57206369/…

David 26.07.2019 10:20

Другие вопросы по теме