viewmodel随活动或其所连接的片段而生或死。这产生了某些后果,我无法理解为什么没有人询问(如果我们将导航架构融入图片中)。
根据最新的android博客和导航框架的工作方式,建议我们进入单活动多片段诗句。
假设我有以下应用程序设计。
Activity A (Application Entry Point)
----------
Fragment (A) (Uses ViewModel AB)
Fragment (B) (Uses ViewModel AB)
Fragment (C) (Uses ViewModel CDE)
Fragment (D) (Uses ViewModel CDE)
Fragment (E) (Uses ViewModel CDE)
现在,由于我使用共享视图模型,这意味着我的视图模型将附加到活动。然而,这似乎是泄漏的。就像如果我从A到E一路遍历,现在回来弹出片段到片段B,视图模型CDE应该被销毁,但它不会被销毁,因为它与活动相连。
此外,我们无法将视图模型连接到片段,因为我们将共享它们的数据。
事实上,只有我提出这个问题,这使我相信我的理解是错误的。如果我能正确了解情况,我会很高兴。
我假设这是你的问题:
就像我从A遍历到E,现在返回时弹出一个片段到另一个片段B一样,viewmodel CDE应该被销毁,但它不会被销毁,因为它与活动相连接。
您希望使用ViewModel在多个片段之间共享数据,但您希望确保当片段导航到特定屏幕时,ViewModel的数据将被销毁。
我对此的建议解决方案是:
>
在ViewModel类中创建Destroy Data函数,该函数将通过将ViewModel的值覆盖为空值来销毁其数据,例如“”
class CDEViewModel : ViewModel() {
var dataString: String = ""
fun destroyViewModelData() { // Function that will Destroythe Data
dataString= ""
}
}
现在,只要需要确保ViewModel数据被清除/销毁,就可以在片段中调用destroyViewModelData函数
class FragmentE {
private lateinit var cdeViewModel : CDEViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initialize your ViewModel
cdeViewModel = ViewModelProviders.of(this).get(CDEViewModel ::class.java)
}
override fun onStart() {
super.onStart()
// Set your Value Here
cdeViewModel.dataString = "String 1"
}
override fun onStop() {
super.onStop()
// Reset/Destroy Data when Screen is Being Close/Navigate to other Screen
// After Call this function, in Whatever Screen, the ViewModel previous Set ""String 1"" Data is Clear/Destroy and become "" empty value.
cdeViewModel.destroyViewModelData()
}
}
在您的例子中,可以在FragmentE的onStop()处调用destroyViewModelData函数,因此当您从FragmentE导航到FragmentB时,CDEViewModel的数据都变成了“空字符串”,这意味着它已被重置/销毁。
希望这个简单的解决方案能有所帮助。非常感谢。
由于导航2.1.0-alpha02(在导航图2.1.0中稳定),您可以通过navGraphViewModels()创建范围位于导航图级别的视图模型。
要使ViewModel不附加到活动或单个片段,必须创建一个嵌套的导航图,并在该图的范围内请求ViewModel的实例。这将导致当您在嵌套导航图中时,ViewModel将活动,并且嵌套图中的片段将重用ViewModel的同一实例。
通过这种方式,您可以有几个嵌套的导航图,每个图都有一个ViewModel实例,该实例将在组成该图的片段之间共享。
我将遵循您相同的片段和视图模型分布:
MainActivity (Application Entry Point)
----------
Fragment (A) (Uses SharedViewModelOne) -> navGraphOne
Fragment (B) (Uses SharedViewModelOne) -> navGraphOne
Fragment (C) (Uses SharedViewModelTwo) -> navGraphTwo
Fragment (D) (Uses SharedViewModelTwo) -> navGraphTwo
要实现这一点,您必须遵循以下步骤:
>
...
apply plugin: 'kotlin-kapt'
android {
...
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies{
...
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
kapt 'androidx.lifecycle:lifecycle-compiler:2.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.1'
}
选择将共享同一ViewModel的片段,并将其添加到嵌套的导航图中。为此,请在导航图设计器中选择片段,然后右键单击它们并选择“移动到嵌套图”
在本例中,我将片段A和片段B添加到navGraphOne,将片段C和片段D添加到navGraphTwo。
在此处查找有关嵌套导航图的详细信息
在片段A和片段B中,请求SharedViewModelOne的实例。
private val modelOne: SharedViewModelOne by navGraphViewModels(R.id.navGraphOne) {
//defaultViewModelProviderFactory or the ViewModelProvider.Factory you are using.
defaultViewModelProviderFactory
}
override fun onCreateView(
..
): View? {
...
//use binding.lifecycleOwner = viewLifecycleOwner
//to make sure the observer disappears when the fragment is destroyed
modelOne.item.observe(viewLifecycleOwner, Observer {
//do Something
})
...
}
在片段C和片段D中,请求SharedViewModelTwo的实例。
private val modelTwo: SharedViewModelTwo by navGraphViewModels(R.id.navGraphTwo) {
//defaultViewModelProviderFactory or the ViewModelProvider.Factory you are using.
defaultViewModelProviderFactory
}
override fun onCreateView(
..
): View? {
...
//use binding.lifecycleOwner = viewLifecycleOwner
//to make sure the observer disappears when the fragment is destroyed
modelTwo.item.observe(viewLifecycleOwner, Observer {
//do Something
})
...
}
然后要验证只创建了ViewModel的单个实例并且它在片段之间共享,请覆盖onCleared()
方法并在ViewModel的init{}
中添加检查点。
例如:
class SharedViewModelOne : ViewModel() {
private val _item = MutableLiveData<String>()
val item : LiveData<String>
get() = _item
init {
Log.d(TAG, "SharedViewModelOne has created!")
}
override fun onCleared() {
super.onCleared()
Log.d(TAG, "SharedViewModelOne has removed!")
}
}
遵循前面的步骤后,您应该能够创建一个ViewModel,该ViewModel将在属于同一嵌套导航图的片段之间共享。ViewModel仅在您位于图内时有效,如果您离开它,它将被销毁。
如果您觉得有些事情不是很清楚,您可以查看此回购并澄清您的疑虑。
这确实是一个问题,并已向谷歌报告。
幸运的是,自从导航2.1.0-alpha02(在2.1.0中稳定)以来,这个问题已经解决了。您可以在此处找到更改日志和文档。
现在,您可以通过Kotlin用户的navGraphViewModels()属性委托或使用添加到NavController的getViewModelStore()API创建在导航图级别范围内的视图模型。
首先,您应该在导航图设计器中选择一些片段,然后右键单击它们并选择“移动到嵌套图”以创建一个新的图,该图将用作如下“范围”:
class DetailFr : Fragment() {
private val vm: DetailViewModel by navGraphViewModels(R.id.main_nav_graph)
}
您可以在此处了解有关嵌套图
的更多信息。
每个应用都会有自己的导航,为了让每个应用都能很方便共享自己的导航数据,我们需要一种良好的应用间导航共享机制,而这种机制就是程序内部可以访问的内部 api. 导航配置文件 导航配置文件就是用于配置应用有哪些导航api,此文件会返回一个数组,数组的子项就一个应用内部 api 链接的地址,但不用带应用名; 导航配置文件是位于应用根目录下的nav.php文件,以 portal 应用为例,就是 app/po
每个应用都会有自己的导航,为了让每个应用都能很方便共享自己的导航数据,我们需要一种良好的应用间导航共享机制,而这种机制就是程序内部可以访问的内部 api. 导航配置文件 导航配置文件就是用于配置应用有哪些导航api,此文件会返回一个数组,数组的子项就一个应用内部 api 链接的地址,但不用带应用名; 导航配置文件是位于应用根目录下的nav.php文件,以 portal 应用为例,就是 app/po
当我试图在我的Android应用程序中处理进程死亡时,我注意到范围为导航图的ViewModel在从进程死亡重新创建时崩溃。下面是使用ViewModel的ViewModel和片段的代码。 在我的片段中,我得到了如下引用 现在,当我试图通过在模拟器中启动应用程序,将其放在后台,然后用android工作室的“终止应用程序”按钮杀死进程来测试应用程序的进程死亡时,它在重新创建时崩溃,并出现以下错误 然而,
我正在一个新的Android应用程序上使用导航组件,但我不知道怎么做 首先,我有我的主活动,我有main_navigation_graph 主要活动 NavHostFragment main_navigation_graph里面有3个碎片 这里一切都很好。问题是当我到达最后一个片段时,因为在这个片段上,我想根据BottomNavigationView输入(暂时)显示一些子片段(在新的NavHost
我有两个屏幕链接到两个标签按钮 < li >名称 < li >持续时间 单击“下一步”按钮时,我希望选项卡移动到第二个按钮。在我的视图模型中,这是我对“下一步”按钮的命令 这是我的代码示例 第二个视图将全屏打开,而不是移动到下一个选项卡。 屏幕已连接 第一屏 第二屏幕 我看到的屏幕
例如,以下结果结构将是理想的: -只读接口 -可变实现 或者更好的是,有没有一种不同的方式来实现这一点?