web-dev-qa-db-ja.com

ナビゲーショングラフスコープでビューモデルを挿入:NavControllerはonCreate()の前には使用できません

アプリケーションでナビゲーションコンポーネントを使用しており、同じグラフにある複数のフラグメント間で共有ViewModelも使用しています。次に、このグラフスコープで this を使用してViewModelをインスタンス化します。

ご存じのとおり、断片的に onAttachにオブジェクト(ViewModel、.. etc)を挿入する必要があります

しかし、これを実行したい場合(onAttachにグラフスコープを含むViewModelを注入)、このエラーが発生します。

IllegalStateException: NavController is not available before onCreate()

私がこれをどうやってできるか知っていますか?

4
beigirad

つまり、ViewModelにダガーProviderまたはLazyをレイジーに提供できます。

長い説明は:

あなたの注射ポイントは正しいです。 https://dagger.dev/Android#when-to-injectによると

DaggerActivityは、super.onCreate()を呼び出す前に、onCreate()ですぐにAndroidInjection.inject()を呼び出します。DaggerFragmentは、onAttach()でも同じことを行います。

問題は、AndroidがActivityに付けられたFragmentsFragmentMangerを再作成するときと、NavControllerを指定できます。

  1. Activityが付いているFragmentsはOSによって破棄されます(「開発者設定」の「アクティビティを保持しない」で再現できます)
  2. ユーザーがActivityに戻り、OSがActivityの再作成を続行します
  3. Activityは、再作成中にsetContentViewを呼び出します。
  4. これにより、FragmentsFragmentManagerが再接続されます。これには、Fragment#onAttachの呼び出しが含まれます。
  5. FragmentFragment#onAttachに挿入されます
  6. ダガーはNavControllerを提供しようとします

しかし、Activity#onCreateがまだ完了していないため、この時点ではNavControllerからActivityを取得できません。

IllegalStateException: NavController is not available before onCreate()

私が見つけた解決策は、NavCotrollerまたはNavControllerに依存するもの(ViewModelなど)を注入することです。Android NavControllerを使用してnavスコープのVideModels)を遅延取得します。これは2つの方法で実行できます。

  • Lazy
  • Provided

(参照: https://proandroiddev.com/dagger-2-part-three-new-possibilities-3daff12f7ebf

つまり、ViewModelFragmentに挿入するか、次のようなナビゲーターの実装を使用します。

    @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を使用する必要がありますが、これはこの問題を解決するために私が見た唯一の回避策です。フラグメントとアクティビティの不条理なライフサイクルを追跡することは非常に難しいので、それらを非難します)。

4
GaRRaPeTa

...オブジェクト(ViewModelなど)をonAttachに挿入する必要があります...

現在、ソースコードから、_androidx.navigation_パッケージによって提供される元のby navGraphViewModels(R.id.nav_graph)委任プロパティを使用したそのようなインジェクションはできません

findNavController().getBackStackEntry(navGraphId) および

public final NavController getNavController() それは次のように述べています:

_ * 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

0
CHAN