组合创建新的 ViewModel 实例
Compose creating new ViewModel instance
我在一个慢慢采用 Jetpack Compose 的项目中工作。它主要是一个 Activity
多个 Fragment
应用程序,我们在其中使用 Android 的导航组件来处理到每个屏幕 (Fragment
) 的转换。只要有可能,我们只会用可组合项替换 Fragment
s 的 XML 布局。
目前案件处理情况如下:
一个。 Fragment
s 显示可组合项并处理导航:
class ScreenFragment : Fragment() {
// For observing events that trigger navigation
private val viewModel by lazyViewModel { ScreenViewModel() }
override fun onCreateView( ... ): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(DisposeOnLifecycleDestroyed(viewLifecycleOwner))
setContent {
AppTheme {
Screen(onBackPressed = { findNavController().navigateUp() })
}
}
}
}
...
}
乙。处理其他所有 UI 相关的可组合项:
@Composable
fun CreatePassword(
onBackPressed: () -> Unit,
) {
// For observing UI states and events
val viewModel: CreatePasswordViewModel = viewModel()
...
}
如您所见,我们的 Fragment
和可组合项中都有屏幕 ViewModel
的参考。到目前为止,这一直运行良好,可组合的 viewModel()
函数总是返回 Fragment
的 ViewModel
.
的相同现有实例
当我们需要在可组合项上引用范围为 Activity
的 ViewModel
时,问题就来了:
- 我们在
Activity
上创建 ViewModel
:
class MainActivity : AppCompatActivity() {
private val viewModel by lazyViewModel { MainViewModel() }
...
}
- 在
Fragment
上为 MainActivity
的 ViewModel
获取参考
class MainFragment : Fragment() {
private val viewModel: MainViewModel by viewModels(::requireActivity)
...
}
- 如上所示,我们获得了可组合项的 ViewModel 引用(项目 B)
通过这样做,Fragment
具有与 Activity
相同的实例,但可组合项没有。
我的问题是,
是否可以在可组合项中获取 Activity
的 ViewModel
的引用? 现在我只是传递 Fragment
的 ViewModel
作为我的主要可组合屏幕的参数。
我通过向我的可组合项提供 ViewModelStoreOwner
来设法传递 Activity
的 ViewModel
,如下所示:
class ScreenFragment : Fragment() {
// For observing events that trigger navigation
private val viewModel by lazyViewModel { ScreenViewModel() }
override fun onCreateView( ... ): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(DisposeOnLifecycleDestroyed(viewLifecycleOwner))
setContent {
val viewModelStoreOwner =
compositionLocalOf<ViewModelStoreOwner> { requireActivity() }
AppTheme {
CompositionLocalProvider(
LocalViewModelStoreOwner provides viewModelStoreOwner.current
) {
Screen(onBackPressed = { findNavController().navigateUp() })
}
}
}
}
}
...
}
听起来像是一个经典的依赖问题,此时我会考虑使用某种依赖注入库,并确保将 viewModel
实例作为单例提供。
我可以推荐 Koin:
https://insert-koin.io/
或者,最近流行的 Hilt:
https://developer.android.com/training/dependency-injection/hilt-android
使用良好的 DI 后,您可以在撰写函数中获得 viewModel
的实例。
我在一个慢慢采用 Jetpack Compose 的项目中工作。它主要是一个 Activity
多个 Fragment
应用程序,我们在其中使用 Android 的导航组件来处理到每个屏幕 (Fragment
) 的转换。只要有可能,我们只会用可组合项替换 Fragment
s 的 XML 布局。
目前案件处理情况如下:
一个。 Fragment
s 显示可组合项并处理导航:
class ScreenFragment : Fragment() {
// For observing events that trigger navigation
private val viewModel by lazyViewModel { ScreenViewModel() }
override fun onCreateView( ... ): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(DisposeOnLifecycleDestroyed(viewLifecycleOwner))
setContent {
AppTheme {
Screen(onBackPressed = { findNavController().navigateUp() })
}
}
}
}
...
}
乙。处理其他所有 UI 相关的可组合项:
@Composable
fun CreatePassword(
onBackPressed: () -> Unit,
) {
// For observing UI states and events
val viewModel: CreatePasswordViewModel = viewModel()
...
}
如您所见,我们的 Fragment
和可组合项中都有屏幕 ViewModel
的参考。到目前为止,这一直运行良好,可组合的 viewModel()
函数总是返回 Fragment
的 ViewModel
.
当我们需要在可组合项上引用范围为 Activity
的 ViewModel
时,问题就来了:
- 我们在
Activity
上创建ViewModel
:
class MainActivity : AppCompatActivity() {
private val viewModel by lazyViewModel { MainViewModel() }
...
}
- 在
Fragment
上为MainActivity
的ViewModel
获取参考
class MainFragment : Fragment() {
private val viewModel: MainViewModel by viewModels(::requireActivity)
...
}
- 如上所示,我们获得了可组合项的 ViewModel 引用(项目 B)
通过这样做,Fragment
具有与 Activity
相同的实例,但可组合项没有。
我的问题是,
是否可以在可组合项中获取 Activity
的 ViewModel
的引用? 现在我只是传递 Fragment
的 ViewModel
作为我的主要可组合屏幕的参数。
我通过向我的可组合项提供 ViewModelStoreOwner
来设法传递 Activity
的 ViewModel
,如下所示:
class ScreenFragment : Fragment() {
// For observing events that trigger navigation
private val viewModel by lazyViewModel { ScreenViewModel() }
override fun onCreateView( ... ): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(DisposeOnLifecycleDestroyed(viewLifecycleOwner))
setContent {
val viewModelStoreOwner =
compositionLocalOf<ViewModelStoreOwner> { requireActivity() }
AppTheme {
CompositionLocalProvider(
LocalViewModelStoreOwner provides viewModelStoreOwner.current
) {
Screen(onBackPressed = { findNavController().navigateUp() })
}
}
}
}
}
...
}
听起来像是一个经典的依赖问题,此时我会考虑使用某种依赖注入库,并确保将 viewModel
实例作为单例提供。
我可以推荐 Koin: https://insert-koin.io/
或者,最近流行的 Hilt: https://developer.android.com/training/dependency-injection/hilt-android
使用良好的 DI 后,您可以在撰写函数中获得 viewModel
的实例。