【Navigation3】结合ViewModel(二)

背景

在使用ViewModel时,一般会考虑使用hilt来依赖注入ViewModel对象。在使用compose时,安卓官方推荐使用androidx.hilt.lifecycle.viewmodel.compose库中的hiltViewModel()方法,来注入ViewModel对象

在Nav3中使用Hilt注入ViewModel对象

  1. 配置环境
  2. 完善lifecycle-viewmodel-navigation3库配置
  3. 使用hiltViewModel()完成对象注入

环境配置

  1. 导入Nav3相关库
  2. 导入androidx.hilt.lifecycle.viewmodel.compose
  3. 导入Hilt相关库
  4. 导入lifecycle-viewmodel-navigation3

使用案例

kotlin 复制代码
/*
 * Copyright 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.nav3recipes.passingarguments.viewmodels.hilt

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.compose.dropUnlessResumed
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
import androidx.navigation3.ui.NavDisplay
import com.example.nav3recipes.content.ContentBlue
import com.example.nav3recipes.content.ContentGreen
import com.example.nav3recipes.passingarguments.viewmodels.basic.RouteB
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel

data object RouteA
data class RouteB(val id: String)

@AndroidEntryPoint
class HiltViewModelsActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        setEdgeToEdgeConfig()
        super.onCreate(savedInstanceState)
        setContent {
            val backStack = remember { mutableStateListOf<Any>(RouteA) }

            NavDisplay(
                backStack = backStack,
                onBack = { backStack.removeLastOrNull() },

                // In order to add the `ViewModelStoreNavEntryDecorator` (see comment below for why)
                // we also need to add the default `NavEntryDecorator`s as well. These provide
                // extra information to the entry's content to enable it to display correctly
                // and save its state.
                entryDecorators = listOf(
                    rememberSaveableStateHolderNavEntryDecorator(),
                    rememberViewModelStoreNavEntryDecorator()
                ),
                entryProvider = entryProvider {
                    entry<RouteA> {
                        ContentGreen("Welcome to Nav3") {
                            LazyColumn {
                                items(10) { i ->
                                    Button(onClick = dropUnlessResumed {
                                        backStack.add(RouteB("$i"))
                                    }) {
                                        Text("$i")
                                    }
                                }
                            }
                        }
                    }
                    entry<RouteB> { key ->
                        val viewModel = hiltViewModel<RouteBViewModel, RouteBViewModel.Factory>(
                            // Note: We need a new ViewModel for every new RouteB instance. Usually
                            // we would need to supply a `key` String that is unique to the
                            // instance, however, the ViewModelStoreNavEntryDecorator (supplied
                            // above) does this for us, using `NavEntry.contentKey` to uniquely
                            // identify the viewModel.
                            //
                            // tl;dr: Make sure you use rememberViewModelStoreNavEntryDecorator()
                            // if you want a new ViewModel for each new navigation key instance.
                            creationCallback = { factory ->
                                factory.create(key)
                            }
                        )
                        ScreenB(viewModel = viewModel)
                    }
                }
            )
        }
    }
}

@Composable
fun ScreenB(viewModel: RouteBViewModel) {
    ContentBlue("Route id: ${viewModel.navKey.id} ")
}

@HiltViewModel(assistedFactory = RouteBViewModel.Factory::class)
class RouteBViewModel @AssistedInject constructor(
    @Assisted val navKey: RouteB
) : ViewModel() {

    @AssistedFactory
    interface Factory {
        fun create(navKey: RouteB): RouteBViewModel
    }
}

相关参考文献

Nav3官方文档

Nav3源码示例

相关推荐
你怎么知道我是队长9 小时前
CRC校验C语言实现-CRC8、CRC16、CRC16的直接计算法、查表法
c语言·前端·javascript
Rain50910 小时前
mini-cc 终端 UI:用 React 写 CLI 是什么体验
前端·人工智能·react.js·ui·架构·前端框架·ai编程
wu85877345710 小时前
向量数据库不是银弹:从枚举漏检到 ReACT 多轮召回的实践路径
前端·数据库·react.js
古怪今人10 小时前
[前端]HTML盒模型与尺寸,标准文档流,块级元素、内联元素和行内块,CSS选择器
前端·css
小雨下雨的雨10 小时前
基于鸿蒙PC Electron框架技术完成的表单验证技术详解
前端·javascript·华为·electron·前端框架·鸿蒙
提子拌饭13310 小时前
饮料含糖量查询应用 - 鸿蒙PC用Electron框架完整实现
前端·javascript·华为·electron·前端框架·鸿蒙
JustHappy10 小时前
古法编程秘籍(五):什么是进程和线程?从软件到 CPU 的一次完整旅程
前端·后端·代码规范
爱编程的小金10 小时前
前端请求库的下一个进化方向:从 Promise 到策略化
前端·alova·前端请求库·请求策略
hsg7710 小时前
简述:Jensen Huang‘s Footsteps网站全内容分析
前端·javascript·数据库
珑墨11 小时前
前端 AI 开发通用skill
前端