Можно ли передать ViewModel во фрагмент в конструкторе?

Я использую Koin для DI, но я пытаюсь устранить зависимости от структуры DI, поэтому мой вопрос касается компонентов архитектуры Android в целом.

Можно предоставить экземпляр ViewModel делегатом свойства во фрагменте, но это вызывает связь между фрагментом и структурой DI. Итак, я нашел решение: передать ViewModel во фрагмент в конструкторе. Текущая реализация с Koin выглядит так:

val di = module {
    fragment {
        MyFragment(
            get<MyViewModel>(),
        )
    }
    viewModel {
        MyViewModel(
            get<MyDependency>(),
        )
    }
    //...
}

И это работает. Но есть загвоздка. Поскольку ViewModel создается перед фрагментом, он не следует жизненному циклу фрагмента, и onCleared() не вызывается при уничтожении фрагмента.

Так что мне интересно, как я могу заставить его снова работать?


person oleg.semen    schedule 13.03.2021    source источник


Ответы (2)


Собственно, к Koin вопрос вообще не относится. Для правильного создания ViewModel (привязанного к жизненному циклу) вам понадобится ссылка на ViewModelProvider, который можно создать с помощью фрагмента или действия.

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

Чтобы устранить зависимости от Koin, вы можете обернуть функцию расширения Koin viewModel () в свою собственную функцию, чтобы при необходимости можно было поменять местами DI.

person Aleksei Potapkin    schedule 23.04.2021
comment
Из того, что я вижу, ViewModelProvider имеет ссылку на ViewModelStoreOwner, который является интерфейсом. Активность и фрагмент являются реализациями этого интерфейса по умолчанию, но я считаю, что модуль Koin (или область видимости, или что-то еще в Koin) может играть роль ViewModelStoreOwner. Или я что-то пропустил по поводу привязки ViewModelProvider к активностям и фрагментам? - person oleg.semen; 23.05.2021
comment
Но вам нужно, чтобы ViewModelStoreOwner был lifecycleOwner, если вы хотите привязать ViewModel к жизненному циклу активности / фрагмента. Или не будет правильного вызова onCleared (), когда активность прекратится. - person Aleksei Potapkin; 26.05.2021

На базовом уровне фрагмент - это объект, поэтому вы можете передавать параметры в конструктор фрагмента. Однако это не очень хорошая практика, и вам всегда следует избегать этого, потому что Android - это система, основанная на событиях, поэтому вы должны вести себя соответствующим образом. Из-за этой плохой практики можно перечислить так много разных проблем, но давайте сосредоточимся на вашей проблеме. Внутри метод onCleared () модели представления вызывается viewModelStoreOwner, который реализуется действиями и фрагментами. Следовательно, действие или фрагмент должны знать об этой модели представления. Самый простой способ обеспечить такую ​​осведомленность - использовать метод расширения viewModels. (https://developer.android.com/kotlin/ktx#fragment). Он напрямую связывает вашу модель представления с вашим фрагментом или действием внутри. Однако с этим решением мы должны рассмотреть другую проблему: как мы внедряем наши другие объекты (репозитории, варианты использования и т. Д.) В наши модели представления. Для этого нам нужно реализовать фабрику пользовательских моделей представления. Я не уверен, что эта часть требуется для Koin, поэтому вы можете посмотреть https://insert-koin.io/docs/reference/koin-android/viewmodel/.

person M.ekici    schedule 13.03.2021
comment
Если вам нужно больше технических объяснений, я могу ответить. - person M.ekici; 14.03.2021