0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ナビゲーショングラフ内でviewModel()を使用した場合、取得できるViewModelは独自のViewModelStoreOwnerに紐づいている。ActivityやFragmentに紐づいたものは取得できない。

Last updated at Posted at 2022-10-03

まとめ

  • ナビゲーショングラフ内でviewModel()を使用した場合、取得できるViewModelActivityFragmentのそれとは別の、独自のViewModelStoreOwnerに紐づいています。
  • そのナビゲーションの乗っているActivityFragmentに紐づいたものは取得できません。
  • 特にAndroidViewと組み合わせて使用した場合、ActivityFragmentのライフライクルに紐づいたものを取得できることを無意識のうちに期待しがちなので注意。
  • ナビゲーショングラフはデスティネーション毎(パス毎)に独立したViewModelStoreOwnerを持ちます。

つまりこういうこと

以下のようなViewModelクラスとActivityがあった時に、

SampleViewModel.kt
class SampleViewModel : ViewModel() {

    // 新しいインスタンスができるたびにユニークなIDを振ります。
    private val id = UUID.randomUUID()

    fun getId() = id
}
MainActivity.kt
class MainActivity : ComponentActivity() {

    private val viewModel: SampleViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            Log.i(TAG, "setContent viewModel id : " + viewModel.getId())
            MakeTransparentAppTheme {
                MakeNavigation()
            }
        }
    }

}


@SuppressLint("CoroutineCreationDuringComposition")
@Composable
private fun MakeNavigation(viewModel: SampleViewModel = viewModel()) {
    Log.i(TAG, "MakeNavigation viewModel id : " + viewModel.getId())

    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "home") {
        composable("home") {
            val viewModel1: SampleViewModel = viewModel()
            Log.i(TAG, "NavStackEntry Home1 viewModel id : " + viewModel1.getId())
            Home1()
        }

        composable("home2") {
            val viewModel2: SampleViewModel = viewModel()
            Log.i(TAG, "NavStackEntry Home1 viewModel id : " + viewModel2.getId())
            Home2()
        }
    }


    rememberCoroutineScope().launch {
        delay(1000)
        Log.i(TAG, "navigate to Home2")
        navController.navigate("home2")
    }

}

@Composable
fun Home1(viewModel: SampleViewModel = viewModel()) {
    Log.i(TAG, "Home1 viewModel id : " + viewModel.getId())
    Home2()
}


@Composable
fun Home2(viewModel: SampleViewModel = viewModel()) {
    Log.i(TAG, "Home2 viewModel id : " + viewModel.getId())
    Home3()
}


@Composable
fun Home3(viewModel: SampleViewModel = viewModel()) {
    Log.i(TAG, "Home3 viewModel id : " + viewModel.getId())
}

Logcatはこのようになります。(抜粋)

setContent viewModel id : 4971f3d3-bfc0-4775-b8b0-7180ab8759d1 <-- ActivityのViewModelStoreOwnerに紐づいているViewModel
MakeNavigation viewModel id : 4971f3d3-bfc0-4775-b8b0-7180ab8759d1 <-- ActivityのViewModelStoreOwnerに紐づいているViewModel
// ここから"home"パスを表示
NavHost is called
NavStackEntry Home1 viewModel id : aaebbc8a-759c-4885-8524-ffb07136c917  <-- (Activityではなく)独自のViewModelStoreOwnerに紐づいているViewModel="home"パスのNavStackEntryのViewModelStoreOwnerに紐づいているViewModel
Home1 viewModel id : aaebbc8a-759c-4885-8524-ffb07136c917  <-- "home"パスのNavStackEntryと同じ独自のViewModelStoreOwnerに紐づいているViewModel
Home2 viewModel id : aaebbc8a-759c-4885-8524-ffb07136c917  <-- "home"パスのNavStackEntryと同じ独自のViewModelStoreOwnerに紐づいているViewModel
Home3 viewModel id : aaebbc8a-759c-4885-8524-ffb07136c917  <-- "home"パスのNavStackEntryと同じ独自のViewModelStoreOwnerに紐づいているViewModel
// ここから"home2"パスへ移動処理
navigate to Home2
NavStackEntry Home1 viewModel id : aaebbc8a-759c-4885-8524-ffb07136c917  <-- "home"パスのNavStackEntryと同じ独自のViewModelStoreOwnerに紐づいているViewModel="home2"パスのNavStackEntryのViewModelStoreOwnerに紐づいているViewModel
NavStackEntry Home2 viewModel id : e38c3070-860a-4f40-bdca-37b6b65ec999  <-- Activityとも"home"のパスの時とも違う独自のViewModelStoreOwnerに紐づいているViewModel
Home2 viewModel id : e38c3070-860a-4f40-bdca-37b6b65ec999  <-- "home2"パスのNavStackEntryと同じ独自のViewModelStoreOwnerに紐づいているViewModel
Home3 viewModel id : e38c3070-860a-4f40-bdca-37b6b65ec999  <-- "home2"パスのNavStackEntryと同じ独自のViewModelStoreOwnerに紐づいているViewModel
NavStackEntry Home2 viewModel id : e38c3070-860a-4f40-bdca-37b6b65ec999  <-- "home2"パスのNavStackEntryと同じ独自のViewModelStoreOwnerに紐づいているViewModel

細かく

上記の通りで、またナビゲーションが画面から画面への遷移を表現するために使われることが多いことを考えれば納得の動きです。
ですが最初この動きを把握しておらず、どうなっているのかコードを追ってみて理解しました。
せっかくコードを追ったので備忘録として要点をかいつまんでですが残しておきます。

環境

  • Jetpack Compose ライブラリ : v1.2.0

コンポーズ可能なメソッド内でviewModel()を呼んだ時何が起きるのか

コンポーズ可能なメソッド内でviewModel()を呼んだ時は以下のようなメソッドが呼ばれています。
(コード内のXXXで始まるコメント文は私が足したものです。)

ViewModel.kt
@Suppress("MissingJvmstatic")
@Composable
public inline fun <reified VM : ViewModel> viewModel(
    viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
    }, // XXX 引数なしでviewModel()を呼ぶと、viewModelStoreOwnerとして
       // LocalViewModelStoreOwner.currentが(Nullでなければ)使われます。
    key: String? = null,
    factory: ViewModelProvider.Factory? = null,
    extras: CreationExtras = if (viewModelStoreOwner is HasDefaultViewModelProviderFactory) {
        viewModelStoreOwner.defaultViewModelCreationExtras
    } else {
        CreationExtras.Empty
    }
): VM = viewModel(VM::class.java, viewModelStoreOwner, key, factory, extras)

第一引数の、

    viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
    }

のあたりで、viewModelStoreOwnerとしてLocalViewModelStoreOwner.currentが使われています。(…①)

ナビゲーショングラフ内で何をしているか

ちょっと話は飛びますが、次はコンポーズ可能なメソッドの中でNavHostメソッドを呼んだ時の動きについて追います。
コンポーズ可能なメソッドの中でNavHostメソッドを呼んだ時は以下のような定義のメソッドが呼ばれます。

NavHost.kt
@Composable
public fun NavHost(
    navController: NavHostController,
    startDestination: String,
    modifier: Modifier = Modifier,
    route: String? = null,
    builder: NavGraphBuilder.() -> Unit
) {
    NavHost(
        navController,
        remember(route, startDestination, builder) {
            navController.createGraph(startDestination, route, builder)
        },
        modifier
    )
}

この中で呼ばれているNavHostメソッドは以下のような定義になっています。
(コード内のXXXで始まる日本語のコメント文は私が足したものです。)

NavHost.kt
@Composable
public fun NavHost(
    navController: NavHostController,
    graph: NavGraph,
    modifier: Modifier = Modifier
) {
    val lifecycleOwner = LocalLifecycleOwner.current
    val viewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "NavHost requires a ViewModelStoreOwner to be provided via LocalViewModelStoreOwner"
    } // XXX ここでもviewModelStoreOwnerとしてLocalViewModelStoreOwner.currentが使われています。

    val onBackPressedDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
    val onBackPressedDispatcher = onBackPressedDispatcherOwner?.onBackPressedDispatcher

    // Setup the navController with proper owners
    navController.setLifecycleOwner(lifecycleOwner)
    navController.setViewModelStore(viewModelStoreOwner.viewModelStore) // XXX navControllerのViewModelStoreは
                                                                        // LocalViewModelStoreOwner.current.viewModelStoreになりました。

    // (中略)

    val visibleEntries by remember(navController.visibleEntries) {
        navController.visibleEntries.map {
            it.filter {
                    entry -> entry.destination.navigatorName == ComposeNavigator.NAME
            }
        }
    }.collectAsState(emptyList())  // XXX navController.visibleEntriesの値(のうちCompose用のもの)をStateにして
                                   // visibleEntriesとして持ちます。




    val backStackEntry = visibleEntries.lastOrNull() // XXX visibleEntriesの最後のアイテムを
                                                     // backStackEntryとしています。


    var initialCrossfade by remember { mutableStateOf(true) }
    if (backStackEntry != null) {
        // while in the scope of the composable, we provide the navBackStackEntry as the
        // ViewModelStoreOwner and LifecycleOwner
        Crossfade(backStackEntry.id, modifier) {
            val lastEntry = visibleEntries.last { entry ->
                it == entry.id
            }// XXX visibleEntriesの最後のアイテムを
             // 今度はlastEntryとしています。

            // We are disposing on a Unit as we only want to dispose when the CrossFade completes
            DisposableEffect(Unit) {
                if (initialCrossfade) {
                    // There's no animation for the initial crossfade,
                    // so we can instantly mark the transition as complete
                    visibleEntries.forEach { entry ->
                        composeNavigator.onTransitionComplete(entry)
                    }
                    initialCrossfade = false
                }
                onDispose {
                    visibleEntries.forEach { entry ->
                        composeNavigator.onTransitionComplete(entry)
                    }
                }
            }

            lastEntry.LocalOwnersProvider(saveableStateHolder) {
                (lastEntry.destination as ComposeNavigator.Destination).content(lastEntry)
            } // XXX lastEntry#.LocalOwnersProviderメソッドを呼んでいます。
        }
    }


    // (以下略)

}

ここでの処理の大事なところは、最後の

            lastEntry.LocalOwnersProvider(saveableStateHolder) {
                (lastEntry.destination as ComposeNavigator.Destination).content(lastEntry)
            } // XXX lastEntry#.LocalOwnersProviderメソッドを呼んでいます。

lastEntry.LocalOwnersProvider部分です。
このlastEntryは少し前の

            val lastEntry = visibleEntries.last { entry ->
                it == entry.id
            }// XXX visibleEntriesの最後のアイテムを
             // 今度はlastEntryとしています。

よりvisibleEntriesの最後のアイテムになっており、

visibleEntriesはさらに少し前の方((中略)の直後)の

    val visibleEntries by remember(navController.visibleEntries) {
        navController.visibleEntries.map {
            it.filter {
                    entry -> entry.destination.navigatorName == ComposeNavigator.NAME
            }
        }
    }.collectAsState(emptyList())  // XXX navController.visibleEntriesの値(のうちCompose用のもの)をStateにして
                                   // visibleEntriesとして持ちます。

より、navController.visibleEntriesの値(のうちCompose用のもの)Stateとしたものです。

ちなみにnavController.visibleEntriesNavBackStackEntryのリストのStateFlowで、現在表示しているパスの画面やバックスタックに積まれているものが変わると変化します。
→つまりNavController.navigateNavController.popBackStackメソッドが呼ばれると変化します。

よって、navController.visibleEntriesの(最後の?)値が変わるたびに、自動的に、先ほど「ここでの処理の大事なところ」とした

            lastEntry.LocalOwnersProvider(saveableStateHolder) {
                (lastEntry.destination as ComposeNavigator.Destination).content(lastEntry)
            } // XXX lastEntry#.LocalOwnersProviderメソッドを呼んでいます。

が呼ばれます。

さて、ではlastEntry.LocalOwnersProviderメソッドが何をしているかですが、このメソッドの定義は以下です。
※ちなみにNavBackStackEntryクラスはViewModelStoreOwnerも実装しています。

NavBackStackEntryProvider.kt
@Composable
public fun NavBackStackEntry.LocalOwnersProvider(
    saveableStateHolder: SaveableStateHolder,
    content: @Composable () -> Unit
) {
    CompositionLocalProvider(
        LocalViewModelStoreOwner provides this,
        LocalLifecycleOwner provides this,
        LocalSavedStateRegistryOwner provides this
    ) {
        saveableStateHolder.SaveableStateProvider(content)
    }
}

最初に注目すべきはCompositionLocalProviderメソッドの第一引数のLocalViewModelStoreOwner provides thisです。
こちらのメソッドの定義は

LocalViewModelStoreOwner.kt
public object LocalViewModelStoreOwner {
    private val LocalViewModelStoreOwner =
        compositionLocalOf<ViewModelStoreOwner?> { null }

    /**
     * Returns current composition local value for the owner or `null` if one has not
     * been provided nor is one available via [ViewTreeViewModelStoreOwner.get] on the
     * current [LocalView].
     */
    public val current: ViewModelStoreOwner?
        @Composable
        get() = LocalViewModelStoreOwner.current
            ?: ViewTreeViewModelStoreOwner.get(LocalView.current)

    /**
     * Associates a [LocalViewModelStoreOwner] key to a value in a call to
     * [CompositionLocalProvider].
     */
    public infix fun provides(viewModelStoreOwner: ViewModelStoreOwner):
        ProvidedValue<ViewModelStoreOwner?> {
            return LocalViewModelStoreOwner.provides(viewModelStoreOwner)
        }
}

の最後のpublic infix fun providesメソッドです。(ちなみに、余談&捕捉ですがinfixメソッドは呼び出し時にメソッド名と引数の間のカッコ( )を省略して書けるメソッドです。)

こちらは何をしているかというと引数で渡されたviewModelStoreOwnerを引数にして、LocalViewModelStoreOwner.providesメソッドを呼んでいます。この、「引数で渡されたviewMOdelStoreOwner」とは今回の場合lastEntry(=「現在表示している画面=NavBackStackEntry)」です。
LocalViewModelStoreOwner.providesメソッドの定義は以下で

CompositionLocal.kt
    @Suppress("UNCHECKED_CAST")
    infix fun provides(value: T) = ProvidedValue(this, value, true)

ProvidedValueクラスの定義は以下です。
要するに「第1フィールドとしてLocalViewModelStoreOwner、第2フィールドとして現在表示しているNavBackStackEntryが入っているdataクラスのようなもの」と覚えておけばいいと思います。

Composer.kt
class ProvidedValue<T> internal constructor(
    val compositionLocal: CompositionLocal<T>,
    val value: T,
    val canOverride: Boolean
)

さて、public fun NavBackStackEntry.LocalOwnersProviderの処理の中身追いに戻ります。ここまでで

NavBackStackEntryProvider.kt
@Composable
public fun NavBackStackEntry.LocalOwnersProvider(
    saveableStateHolder: SaveableStateHolder,
    content: @Composable () -> Unit
) {
    CompositionLocalProvider(
        LocalViewModelStoreOwner provides this,
        LocalLifecycleOwner provides this,
        LocalSavedStateRegistryOwner provides this
    ) {
        saveableStateHolder.SaveableStateProvider(content)
    }
}

CompositionLocalProviderメソッドの第一引数のLocalViewModelStoreOwner provides thisが「第1フィールドとしてLocalViewModelStoreOwner、第2フィールドとして現在表示しているNavBackStackEntryが入っているdataクラスのようなもの」だということが分かりました。
次はCompositionLocalProviderメソッド自体の定義を確認します。定義は以下です。

CompositionLocal.kt
/**
 * [CompositionLocalProvider] binds values to [ProvidableCompositionLocal] keys. Reading the
 * [CompositionLocal] using [CompositionLocal.current] will return the value provided in
 * [CompositionLocalProvider]'s [values] parameter for all composable functions called directly
 * or indirectly in the [content] lambda.
 *
 * @sample androidx.compose.runtime.samples.compositionLocalProvider
 *
 * @see CompositionLocal
 * @see compositionLocalOf
 * @see staticCompositionLocalOf
 */
@Composable
@OptIn(InternalComposeApi::class)
fun CompositionLocalProvider(vararg values: ProvidedValue<*>, content: @Composable () -> Unit) {
    currentComposer.startProviders(values)
    content()
    currentComposer.endProviders()
}

メソッドのjavadocにあるように、

CompositionLocalProvider binds values to ProvidableCompositionLocal keys. 
Reading the CompositionLocal using CompositionLocal.current will return the value 
provided in CompositionLocalProvider's values parameter for all composable functions called directly or indirectly 
in the content lambda.

こちらのメソッドを使用すると(引数のProvidedValueの配列valuesの1要素の第1フィールド)CompositionLocalCompositionLocal.currentを呼んだ時の値を(第2フィールドの)valueに変更。した状態で引数content‘としてわたってきた@Composable () -> Unit`メソッドを呼んでくれます。

つまり、今見ているシチュエーションでは、「第1フィールドとしてLocalViewModelStoreOwner、第2フィールドとして現在表示しているNavBackStackEntryが入っている」ものが渡ってきている状況を見ていたので、このメソッドによりこのCompositionLocalProviderの引数contentLocalViewModelStoreOwner.currentNavBackStackEntryになる状態で実行されることが分かります。(…②)

今見ているシチュエーションでは、contentは前述の呼び出し側で渡している以下のラムダ式です。

NavBackStackEntryProvider.kt
{
        saveableStateHolder.SaveableStateProvider(content)
    }

更に、saveableStateHolder.SaveableStateProvider(content)contentはこれまた前述のNavBackStackEntry.LocalOwnersProviderメソッドの第2引数なのでこの場合以下のラムダ式です。

NavHost.kt
 {
                (lastEntry.destination as ComposeNavigator.Destination).content(lastEntry)
            }

このラムダ式に出てくる、ComposeNavigator.Destination.contentの定義は、

ComposeNavigationr.kt
    /**
     * NavDestination specific to [ComposeNavigator]
     */
    @NavDestination.ClassType(Composable::class)
    public class Destination(
        navigator: ComposeNavigator,
        internal val content: @Composable (NavBackStackEntry) -> Unit
    ) : NavDestination(navigator)

となっています。(…③)

さて、ここで、最初にアプリケーション側からNavHostメソッドを呼ぶ時にナビゲーショングラフを作成するときに使用するNavGraphBuilder.composableメソッドの定義を見てみます。

NavGraphBuilder.kt
public fun NavGraphBuilder.composable(
    route: String,
    arguments: List<NamedNavArgument> = emptyList(),
    deepLinks: List<NavDeepLink> = emptyList(),
    content: @Composable (NavBackStackEntry) -> Unit
) {
    addDestination(
        ComposeNavigator.Destination(provider[ComposeNavigator::class], content).apply {
            this.route = route
            arguments.forEach { (argumentName, argument) ->
                addArgument(argumentName, argument)
            }
            deepLinks.forEach { deepLink ->
                addDeepLink(deepLink)
            }
        }
    )
}

メソッド内の処理の2行目ComposeNavigator.Destination(provider[ComposeNavigator::class], content).apply {より、ComposeNavigator.Destination.contentにはNavGraphBuilder.composableメソッドを呼ぶときに渡すラムダ式部分が来ることが分かりました。(…④)

③、④より

NavBackStackEntryProvider.kt
{
        saveableStateHolder.SaveableStateProvider(content)
    }

saveableStateHolder.SaveableStateProviderに渡しているcontentは「アプリケーション側でNavHostメソッドを呼ぶときに渡すラムダ式の中でNavGraphBuilder.composableメソッドを呼んでいるところで渡すラムダ式部分を、現在表示中のNavBackStackEntryを引数として使用して呼び出す」内容なことが分かりました。

ここでsaveableStateHolder.SaveableStateProviderの方の処理を確認すると、以下のようになっています。

NavBackStackEntryProvider.kt
@Composable
private fun SaveableStateHolder.SaveableStateProvider(content: @Composable () -> Unit) {
    val viewModel = viewModel<BackStackEntryIdViewModel>()
    viewModel.saveableStateHolder = this
    SaveableStateProvider(viewModel.id, content)
    DisposableEffect(viewModel) {
        onDispose {
            viewModel.saveableStateHolder = null
        }
    }
}

ここで見るべきなのは真ん中あたりにあるSaveableStateProvider(viewModel.id, content)の処理です。このメソッドの定義はinterface SaveableStateHolderにあり、実装はSaveableStateHolderImplクラスにあって以下のようになっています。

SaveableStateHolder.kt
    @Composable
    override fun SaveableStateProvider(key: Any, content: @Composable () -> Unit) {
        ReusableContent(key) {
            val registryHolder = remember {
                require(parentSaveableStateRegistry?.canBeSaved(key) ?: true) {
                    "Type of the key $key is not supported. On Android you can only use types " +
                        "which can be stored inside the Bundle."
                }
                RegistryHolder(key)
            }
            CompositionLocalProvider(
                LocalSaveableStateRegistry provides registryHolder.registry,
                content = content
            )
 
            // (以下略)


        }
    }

上の、

            CompositionLocalProvider(
                LocalSaveableStateRegistry provides registryHolder.registry,
                content = content
            )

で、saveableStateHolder.SaveableStateProviderに渡しているcontent==「アプリケーション側でNavHostメソッドを呼ぶときに渡すラムダ式の中でNavGraphBuilder.composableメソッドを呼んでいるところで渡すラムダ式部分を、現在表示中のNavBackStackEntryを引数として使用して呼び出す」を第2引数(=content)として、LocalSaveableStateRegistry.currentを上書きするCompositionLocalProviderを呼んでいます。

さて、ここで、「LocalSaveableStateRegistry.currentを上書きする」といっていますが、そもそもSaveableStateProvider(viewModel.id, content)自体、LocalViewModelStoreOwner.currentLocalViewModelStoreOwner.current,LocalSavedStateRegistryOwner.currentを上書きするCompositionLocalProvidercontentとして呼び出されるものでした。
ゆえにSaveableStateProvider(viewModel.id, content)CompositionLocalProviderで「LocalSaveableStateRegistry.currentを上書き」される前の他のcurrentは上書きされたもの、そしてそれは②よりLocalViewModelStoreOwner.currentNavBackStackEntryです。

つまり、「アプリケーション側でNavHostメソッドを呼ぶときに渡すラムダ式の中でNavGraphBuilder.composableメソッドを呼んでいるところで渡すラムダ式」部分は、LocalViewModelStoreOwner.currentNavBackStackEntryの状態で呼びだされます。(…⑤)

ということにより

コンポーズ可能なメソッド内でviewModel()を呼んだ時何が起きるのかの結論①と、ナビゲーショングラフ内で何をしているかの結論⑤より、
コンポーズ可能なメソッド内でviewModel()を呼んだ時はVideModelStoreOwnerとしてLocalViewModelStoreOwner.currentが使われ、LocalViewModelStoreOwner.currentはナビゲーショングラフ内では、今表示中のNavBackStackEntry(≒今表示中のパスの画面)になることが分かります。

つまり、ナビゲーショングラフはデスティネーション毎(パス毎)に独立したViewModelStoreOwnerを持ち、viewModel()を呼んだ時はパス毎に異なるViewModelのインスタンスが取得出来て、それらはナビゲーショングラフの載っているActivityFragmentのものとは別のインスタンスです。

注意

※ 2022/10/9 追記 : 公開当初下の内容を書いてしまっていましたが、間違っています。
ここまでの議論の通りNavGraphBuilder.composableメソッドのラムダ式の中はNavBackStackEntryに紐づいたViewModelが取得できます。

「注意」セクションを本編部分の執筆を書く前に書いてあったのですが、この記事を書き始めた時点ではそもそもサンプルコードが間違っていて、それにこじつけるような内容になっていました。本編執筆の過程で理解も深まり、以前とは大筋の結論が変わったりしたのですが「注意」の章に関して最後に見直すこともほぼせず最初に書いたものをそのまま公開してしまっていました。。。

現在の理解としては、この記事の話題について、特段注意すべきことはないと考えています。

一応、以前のバージョンのサンプルコードのスニペットとともに残しておきます。

  • 以下の、
    NavHost(navController = navController, startDestination = "home") {
        composable("home") {
            Log.i(TAG, "NavStackEntry Home1 viewModel id : " + viewModel.getId())
            Home1()
        }

        composable("home2") {
            Log.i(TAG, "NavStackEntry Home2 viewModel id : " + viewModel.getId())
            Home2()
        }
    }

Log.i(TAG, "NavStackEntry Home1 viewModel id : " + viewModel.getId())Log.i(TAG, "NavStackEntry Home2 viewModel id : " + viewModel.getId())をしている場所は、引数にNavBackStackEntryが渡ってきているラムダメソッドの場所だが、ここではまだLocalViewModelStoreOwner.currentNavBackStackEntryでない。その中で画面を作成するために呼ばれたHome1()Home2()以降がLocalViewModelStoreOwner.current=NavBackStackEntry

感想

  • 書き終わった勢いで公開せず、ちゃんと補足の章まで含めてすべてきちんと見直すべきですね。。当たり前ですが。。。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?