внедрение модели представления с областью навигационного графа: NavController недоступен до onCreate ()

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

Как вы знаете, во фрагментах мы должны внедрять объекты (ViewModel и т. Д.) В onAttach :

но когда я хочу это сделать (внедрение ViewModel с областью графика в onAttach), возникает эта ошибка:

IllegalStateException: NavController is not available before onCreate()

Ты знаешь, как я могу это сделать?


comment
вы используете NavController в onStart ()?   -  person Mohammed Rampurawala    schedule 18.12.2019
comment
не в onStart(). Я использовал NavController, чтобы получить viewModelStore navGraph в onAttach() @MohammedRampurawala   -  person beigirad    schedule 18.12.2019
comment
Вам необходимо использовать NavController после вызова onCreate (). Это означает, что ваше представление активности инициализировано.   -  person Mohammed Rampurawala    schedule 18.12.2019
comment
Технически вы также можете сделать это внутри onCreate вместо onAttach.   -  person EpicPandaForce    schedule 19.12.2019


Ответы (2)


Короче говоря, вы могли лениво снабдить ViewModel кинжалом Provider или Lazy.

Длинное объяснение:

Твои точки уколов верны. Согласно https://dagger.dev/android#when-to-inject

DaggerActivity вызывает AndroidInjection.inject () сразу в onCreate () перед вызовом super.onCreate (), а DaggerFragment делает то же самое в onAttach ().

Проблема заключается в каком-то состоянии гонки между тем, когда Android воссоздает Activity и Fragments, прикрепленный к FragmentManger, и когда может быть предоставлен NavController. Более конкретно:

  1. один Activity, к которому прикреплен Fragments, уничтожен ОС (может быть воспроизведен с помощью "не сохранять действия" в "настройках разработчика")
  2. пользователь возвращается к Activity, ОС продолжает воссоздавать Activity
  3. Activity вызывает setContentView при воссоздании.
  4. Это приводит к повторному подключению Fragments в FragmentManager, что требует вызова Fragment#onAttach
  5. Fragment вводится в Fragment#onAttach
  6. Кинжал пытается дать NavController

НО вы не можете получить NavController от Activity к этому моменту, поскольку Activity#onCreate еще не закончен, и вы получаете

IllegalStateException: NavController is not available before onCreate()

Решение, которое я нашел, состоит в том, чтобы лениво вводить предоставление NavCotroller или вещей, которые зависят от NavController (например, ViewModel, потому что Android нужен NavController для навигации VideModels). Это можно сделать двумя способами:

  • с Lazy
  • с Provided

(ССЫЛКА: https://proandroiddev.com/dagger-2-part-three-new-possabilities-3daff12f7ebf)

то есть: введите ViewModel в Fragment или реализацию навигатора следующим образом:

    @Inject
    lateinit var viewModel: Provider<ViewModel>

затем используйте это так:

viewModel.get().events.observe(this) {....}

Теперь ViewModel может быть предоставлен Dagger, например:


    @Provides
    fun provideViewModel(
        fragment: Fragment,
        argumentId: Int
    ): CreateMyViewModel {

        val viewModel: CreateMyViewModel
                by fragment.navGraphViewModels(R.id.nested_graph_id)

        return viewModel
    }

Dagger не будет пытаться разрешить подготовку при введении Fragment, но когда он используется, следовательно, состояние гонки будет решено.

Я действительно ненавижу то, что не могу использовать мои модели viewModels напрямую, и мне нужно использовать Provider, но это единственный обходной путь, который я вижу для решения этой проблемы, и я уверен, что это был недосмотр со стороны Google (я не виню их, поскольку отследить абсурдный жизненный цикл фрагментов и действий так сложно).

person GaRRaPeTa    schedule 04.02.2020
comment
Эй, здесь нубик кинжал. как я могу предоставить фрагмент? Я использую @ContributesAndroidInjector abstract fun contributeDetailFragment(): DetailsFragment прямо сейчас - person hushed_voice; 31.07.2020

... мы должны внедрять объекты (ViewModel и т. д.) в onAttach ...

Похоже, что в настоящее время такая инъекция недопустима с исходным делегированным свойством by navGraphViewModels(R.id.nav_graph), предоставленным пакетом androidx.navigation, потому что из исходного кода

_ 3_ и

_ 4_ он заявил, что:

 * Returns the {@link NavController navigation controller} for this navigation host.
 * This method will return null until this host fragment's {@link #onCreate(Bundle)}

И вот несколько обходных путей:

https://github.com/InsertKoinIO/koin/issues/442

person CHAN    schedule 11.03.2020