P. *_*ohm 2 android-navigation android-jetpack-compose
当我在 jetpack compose 中旋转我的应用程序(带导航)时,所有数据都会重置
每次旋转后,它都会进入 Activity 的 onCreate 并再次创建 NavHost 和 ViewModel。我认为这会通过应用程序状态来处理
起始活动:
class NavActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme() {
MyAppApp()
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
包含 NavHost 的应用程序:
@Composable
fun MyAppApp(
appState: MyAppAppState = rememberAppState()
) {
NavHost(
navController = appState.navController,
startDestination = Screen.ProductAddPath.route
)
{
composable(Screen.ProductAddPath.route) {
ProductEditView(
vm = ProductEditViewModel (appState.context)
)
}
}
}
Run Code Online (Sandbox Code Playgroud)
视图模型:
class ProductEditViewModel(context: Context) : ViewModel() {
private val _productName = MutableStateFlow("qsd")
val productName = _productName.asStateFlow()
fun onProductNameChange(it: String) {
_productName.value = it
}
}
Run Code Online (Sandbox Code Playgroud)
我的看法 :
@Composable
fun ProductEditView(vm: ProductEditViewModel) {
Surface( color = MaterialTheme.colorScheme.background) {
val message by vm.productName.collectAsState()
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
OutlinedTextField(
value = message,
onValueChange = { vm.onProductNameChange(it) },
)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我把一个工作项目放在github上
问题是ProductEditViewModel每次上下文发生MyAppAppState变化时都会重新创建,因此所有数据都会重置。init您可以通过使用向视图模型添加一个块来进行一个非常简单的测试println,您会注意到当您旋转屏幕,甚至更改设备的主题时,该init块的内容将再次被触发。通过从该参数中
删除此“问题”将不再发生。ContextProductEditViewModel
Context请注意,将 a 传递给 a是不好的做法ViewModel,当您采用这种方法时,您最终会陷入两种情况。
第一个是破坏 ViewModel 生命周期并使其相对于其声称的用途毫无用处(使数据独立于活动/片段/可组合项的生命周期)。
第二个是导致内存泄漏,很可能导致 ANR。
您可以查看此处和此处,大致了解 ViewModel 的用途、其生命周期如何工作以及一些实际使用示例。
编辑:
创建 ViewModel 实例的方式也很重要。这就是一开始就导致您丢失 ViewModel 数据的细节。
让我们想象一下以下 ViewModel:
class MyViewModel() : ViewModel() {
init {
println("MyViewModel created")
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们像这样实例化它:
MyComposableFuncion(
viewModel: MyViewModel = MyViewModel()
)
Run Code Online (Sandbox Code Playgroud)
我们处理的不是一个会持续存在的实例。这是因为我们刚刚调用了 MyViewModel 实例,并且当屏幕旋转时将重复此操作,从而生成具有所有默认数据的此 ViewModel 的新实例。
如果我们这样做:
import androidx.lifecycle.viewmodel.compose.viewModel
MyComposableFuncion(
viewModel: MyViewModel = viewModel()
)
Run Code Online (Sandbox Code Playgroud)
现在我们使用该viewModel()函数而不是传递MyViewModel(). viewModel()即使屏幕旋转,ViewModel 实例的持久性也在幕后进行处理。
如果 ViewModel 有参数,则需要创建一个ViewModelProvider.Factory提供必要参数的工厂,然后在 viewModel() 函数中传递该工厂。评论中提到的教程
也解释了所有这些信息:
之前我们使用 viewModel() 函数来创建视图模型。不幸的是,viewModel() 函数不允许我们在调用它时简单地传递 Application 引用作为参数。相反,我们需要向函数传递一个自定义 ViewModelProvider Factory 类,该类旨在接受 Application 引用并返回初始化的 MainViewModel 实例。
我的建议是使用一些库来注入依赖项,例如Hilt。但我相信,如果您刚刚开始学习,最重要的是遵循您选择的教程直到最后,这样您就不会混淆事情并变得复杂。
| 归档时间: |
|
| 查看次数: |
1944 次 |
| 最近记录: |