使用Jetpack Compose时,如何更好地注入ViewModel对象



我需要使用导航,而且我还需要在每个屏幕中使用SharedViewModel的实例。这是我试过的。

class MainActivity : ComponentActivity() {
private lateinit var navController: NavHostController
private val viewModel: SharedViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
navController = rememberNavController()
NavGraph(
navController = navController,
sharedViewModel = sharedViewModel
)
}
}
}

如您所见,我将navControllersharedViewModel传递给NavGraph

fun NavGraph(
navController: NavHostController,
sharedViewModel: SharedViewModel
) {
NavHost(
navController = navController,
startDestination = HomeScreen.route
) {
composable(
route = HomeScreen.route
) {
HomeScreen(
sharedViewModel = sharedViewModel
)
}
composable(
route = ProfileScreen.route
) {
ProfileScreen(
sharedViewModel = sharedViewModel
)
}
}
}

为了能够在每个屏幕中使用SharedViewModel,我将一个实例传递给每个可组合函数。这个操作很好。然而,我读到我们可以直接使用在每个可组合的视图模型中注入一个实例

fun HomeScreen(
viewModel: SharedViewModel = hiltViewModel()
) {
//...
}

哪种方法更好?像第一种方法一样,将SharedViewModel的实例传递给所有可组合函数是否更好?还是像第二次那样直接注射更好?

fun HomeScreen(
viewModel: SharedViewModel = hiltViewModel()
) {
//...
}

使用这种方法,实例并不是真正共享的(如果您没有从调用点传递参数,因为您提到了它的默认值,所以可以省略它(。您正在使用viewModel: SharedViewModel的默认值参数,因此将其传递给Composable方法是可选的。如果你不传递它,当它运行时,它将由Hilt在那个可组合作用域中初始化,所以不是共享作用域。您可以通过记录ViewModel的实例来检查这一点

很明显,您可以从调用点传递它,但由于它是默认的named_argument,因此很容易错过传递它。。

您所能做的只是从方法参数中删除初始化,即hiltViewModel()。然后它将是强制性的,并且您必须在调用该方法时传递它。因为在这种情况下,有一个可选的参数实际上没有意义。

如果你不想通过考试,还有另一种方法。。我们可以使用Activity的上下文来创建ViewModel。。

@Composable
fun mainActivity() = LocalContext.current as MainActivity
fun HomeScreen(viewModel: SharedViewModel = hiltViewModel(mainActivity())) {
}

通过这种方式,您也将获得VM的相同实例,从而获得共享实例。在这种情况下,这种可组合性有点局限于单个活动。所以,如果你在其他活动中使用这个,你必须小心它,它会崩溃,并为MainActivity抛出异常。但在单活动体系结构中,它会很好,或者你可以进一步添加对活动的检查。

最新更新