通过视图模型在片段之间共享数据
sharing data between fragments via viewmodels
根据 https://developer.android.com/topic/libraries/architecture/viewmodel 的 "Share data between fragments" 部分,我们被告知在 activity 范围内创建一个 ViewModel 并在片段之间共享它是可行的方法。
这是在 ViewModel 中设置值的 Fragment
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
这是使用属性集
的详细片段
class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}
这是视图模型
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
我的问题很简单。假设 MasterFragment 在单击按钮时在 ViewModel 中设置了一个值,那么在系统终止我们的应用程序并重新启动它之后访问它时我们如何恢复该值?
我们的 DetailFragment 将看不到该值,因为我们是在 MasterFragment 中的按钮单击上设置它的。为了更好地理解这个问题,假设我们有 Fragment A、B、C 和 D,它们共享一个 ViewModel,该 ViewModel 的值 Fragment A B 和 C 一起计算,并将其放在 ViewModel 中供 Fragment D 访问。
现在,当系统终止并重新创建我们的应用程序片段 D 时,该值将不可用。
如果不诉诸脏代码,OnSaveInstance 也无济于事。对于简单的情况,是的,但是像 FragmentA B 和 C 一起做一个值的情况,在那种情况下,OnSaveInstance 就会有问题。
OnSaveInstance 应该在 ViewModel 中,但可惜我认为情况并非如此。有什么想法吗?
如果您在应用重置或终止后仍想获取存储值,您需要将数据保存到 SharedPreferences 或内部 SqLite 数据库,并在应用启动后恢复它。
ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel. The ViewModel remains in memory until the Lifecycle it's scoped to goes away permanently: in the case of an activity, when it finishes, while in the case of a fragment, when it's detached.
My question is simple. Assuming the MasterFragment set a value in the ViewModel on a buttonClick , how would we recover that value when accessing it AFTER THE SYSTEM HAS KILLED OUR APPLICATION AND RESTARTED IT ?.
如果应用程序被用户或系统杀死或重新启动,您将无法恢复该值。
为了解决你从ActivityA、B、C中累积数据并在ActivityD中显示的目的,即使应用程序被杀死或重启,你可以选择任何一种方法以下:
1.共享偏好
2. 本地数据库 Room 或 SQLite
3. 将数据存储在文件中
我建议您对小数据使用 SharedPreference,对大数据和复杂数据使用 Room。
简而言之,ViewModel 临时存储数据以适应方向变化(无需编写 onSaveInstanceState
和 onRestoreInstanceState
的代码)并在 Activity 和 Fragment 之间共享数据。如果 activity 被破坏或片段被分离,数据将丢失。
对于那些使用 Kotlin 的人,请尝试以下方法:
将 androidx ViewModel and LiveData 库添加到您的 gradle 文件
像这样在片段中调用您的视图模型:
class MainFragment : Fragment() {
private lateinit var viewModel: ViewModel
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
// kotlin does not have a getActivity() built in method instead we use activity, which is null-safe
activity?.let {
viemModel = ViewModelProvider(it).get(SharedViewModel::class.java)
}
}
}
根据 https://developer.android.com/topic/libraries/architecture/viewmodel 的 "Share data between fragments" 部分,我们被告知在 activity 范围内创建一个 ViewModel 并在片段之间共享它是可行的方法。
这是在 ViewModel 中设置值的 Fragment
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
这是使用属性集
的详细片段class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}
这是视图模型
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
我的问题很简单。假设 MasterFragment 在单击按钮时在 ViewModel 中设置了一个值,那么在系统终止我们的应用程序并重新启动它之后访问它时我们如何恢复该值?
我们的 DetailFragment 将看不到该值,因为我们是在 MasterFragment 中的按钮单击上设置它的。为了更好地理解这个问题,假设我们有 Fragment A、B、C 和 D,它们共享一个 ViewModel,该 ViewModel 的值 Fragment A B 和 C 一起计算,并将其放在 ViewModel 中供 Fragment D 访问。
现在,当系统终止并重新创建我们的应用程序片段 D 时,该值将不可用。
如果不诉诸脏代码,OnSaveInstance 也无济于事。对于简单的情况,是的,但是像 FragmentA B 和 C 一起做一个值的情况,在那种情况下,OnSaveInstance 就会有问题。
OnSaveInstance 应该在 ViewModel 中,但可惜我认为情况并非如此。有什么想法吗?
如果您在应用重置或终止后仍想获取存储值,您需要将数据保存到 SharedPreferences 或内部 SqLite 数据库,并在应用启动后恢复它。
ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel. The ViewModel remains in memory until the Lifecycle it's scoped to goes away permanently: in the case of an activity, when it finishes, while in the case of a fragment, when it's detached.
My question is simple. Assuming the MasterFragment set a value in the ViewModel on a buttonClick , how would we recover that value when accessing it AFTER THE SYSTEM HAS KILLED OUR APPLICATION AND RESTARTED IT ?.
如果应用程序被用户或系统杀死或重新启动,您将无法恢复该值。
为了解决你从ActivityA、B、C中累积数据并在ActivityD中显示的目的,即使应用程序被杀死或重启,你可以选择任何一种方法以下:
1.共享偏好
2. 本地数据库 Room 或 SQLite
3. 将数据存储在文件中
我建议您对小数据使用 SharedPreference,对大数据和复杂数据使用 Room。
简而言之,ViewModel 临时存储数据以适应方向变化(无需编写 onSaveInstanceState
和 onRestoreInstanceState
的代码)并在 Activity 和 Fragment 之间共享数据。如果 activity 被破坏或片段被分离,数据将丢失。
对于那些使用 Kotlin 的人,请尝试以下方法:
将 androidx ViewModel and LiveData 库添加到您的 gradle 文件
像这样在片段中调用您的视图模型:
class MainFragment : Fragment() { private lateinit var viewModel: ViewModel override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) // kotlin does not have a getActivity() built in method instead we use activity, which is null-safe activity?.let { viemModel = ViewModelProvider(it).get(SharedViewModel::class.java) } } }