防止我的片段和列表在每次显示时都被创建
Prevent my fragment and list from being created every time they are displayed
我第一次在我的应用程序中将数据绑定和片段与导航组件结合使用。在导航和加载我的列表方面一切正常。我遇到的问题是:
当我在列表中并单击其中一项时,我导航到该项目的详细信息片段。但是当我return到列表(onBack)时,片段和列表再次加载,它们被重新创建。
我想要实现的是 不会重新创建片段和列表。它们保持相同的状态,这样当我从细节return开始时,我可以从我离开的地方继续浏览我的列表。
我的代码:
片段
class ListFragment : Fragment() {
private lateinit var viewDataBinding: FragmentListBinding
private lateinit var adapter: ListAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
viewDataBinding = FragmentListBinding.inflate(inflater, container, false).apply {
viewmodel = ViewModelProviders.of(this@ListFragment).get(ListViewModel::class.java)
lifecycleOwner = viewLifecycleOwner
}
return viewDataBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupAdapter()
setupObservers()
}
private fun setupObservers() {
viewDataBinding.viewmodel?.listLive?.observe(viewLifecycleOwner, Observer {
adapter.updateList(it)
})
viewDataBinding.viewmodel?.toastMessage?.observe(viewLifecycleOwner, Observer {
activity?.longToast(it)
})
}
private fun setupAdapter() {
val viewModel = viewDataBinding.viewmodel
if (viewModel != null) {
adapter = ListAdapter(viewDataBinding.viewmodel!!)
val layoutManager = LinearLayoutManager(activity)
list_rv.layoutManager = layoutManager
list_rv.adapter = adapter
}
}
override fun onResume() {
super.onResume()
viewDataBinding.viewmodel?.fetchList()
}
}
片段布局
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="viewmodel"
type="app.example.list.ListViewModel" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="@{safeUnbox(viewmodel.dataLoading) ? View.GONE : View.VISIBLE}" />
</RelativeLayout>
查看模型
class ListViewModel : BaseViewModel() {
val listLive = MutableLiveData<List<Item>>()
fun fetchList() {
dataLoading.value = true
ItemRepository.getInstance().getList() { isSuccess, response ->
dataLoading.value = false
if (isSuccess) {
listLive.value = response?.items
empty.value = false
} else {
empty.value = true
}
}
}
}
我正在使用导航在列表和项目之间导航
itemView.findNavController().navigate(R.id.action_listFragment_to_detailFragment)
由于以下代码,您每次都会重新创建回收列表 -
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupAdapter() //you are setting adapter every time view is getting created
setupObservers()
}
当您使用导航架构进行导航时,每次导航到目的地时,前一个片段将被停止()并在返回时重新创建。因为截至目前导航组件没有后台 issue
但是使用 ViewModel 的全部意义在于不保存片段状态并让 ViewModel 保留数据。您正在使用视图模型,但是您不能每次都在回收视图上设置适配器。
当您从视图模型中获取列表时,只需通知回收视图列表。
您永远不应该在 onResume()
等生命周期方法中重新加载数据 - 这就是为什么每次返回片段时数据都会重新加载。
相反,您应该在 ViewModel 的 init
块中只调用一次 fetchList()
- 这确保它只运行一次:
class ListViewModel : BaseViewModel() {
val listLive = MutableLiveData<List<Item>>()
init {
fetchList()
}
fun fetchList() {
dataLoading.value = true
ItemRepository.getInstance().getList() { isSuccess, response ->
dataLoading.value = false
if (isSuccess) {
listLive.value = response?.items
empty.value = false
} else {
empty.value = true
}
}
}
}
不清楚您的 getList()
方法是如何工作的。现在的写法对于单个回调通常是正确的。如果您的 getList()
实际上返回了一个值流,随着基础数据的变化继续传递回调,那么您必须确保在 onCleared()
中注销该回调(当 ViewModel 被销毁时的回调)。
我第一次在我的应用程序中将数据绑定和片段与导航组件结合使用。在导航和加载我的列表方面一切正常。我遇到的问题是:
当我在列表中并单击其中一项时,我导航到该项目的详细信息片段。但是当我return到列表(onBack)时,片段和列表再次加载,它们被重新创建。
我想要实现的是 不会重新创建片段和列表。它们保持相同的状态,这样当我从细节return开始时,我可以从我离开的地方继续浏览我的列表。
我的代码:
片段
class ListFragment : Fragment() {
private lateinit var viewDataBinding: FragmentListBinding
private lateinit var adapter: ListAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
viewDataBinding = FragmentListBinding.inflate(inflater, container, false).apply {
viewmodel = ViewModelProviders.of(this@ListFragment).get(ListViewModel::class.java)
lifecycleOwner = viewLifecycleOwner
}
return viewDataBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupAdapter()
setupObservers()
}
private fun setupObservers() {
viewDataBinding.viewmodel?.listLive?.observe(viewLifecycleOwner, Observer {
adapter.updateList(it)
})
viewDataBinding.viewmodel?.toastMessage?.observe(viewLifecycleOwner, Observer {
activity?.longToast(it)
})
}
private fun setupAdapter() {
val viewModel = viewDataBinding.viewmodel
if (viewModel != null) {
adapter = ListAdapter(viewDataBinding.viewmodel!!)
val layoutManager = LinearLayoutManager(activity)
list_rv.layoutManager = layoutManager
list_rv.adapter = adapter
}
}
override fun onResume() {
super.onResume()
viewDataBinding.viewmodel?.fetchList()
}
}
片段布局
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="viewmodel"
type="app.example.list.ListViewModel" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="@{safeUnbox(viewmodel.dataLoading) ? View.GONE : View.VISIBLE}" />
</RelativeLayout>
查看模型
class ListViewModel : BaseViewModel() {
val listLive = MutableLiveData<List<Item>>()
fun fetchList() {
dataLoading.value = true
ItemRepository.getInstance().getList() { isSuccess, response ->
dataLoading.value = false
if (isSuccess) {
listLive.value = response?.items
empty.value = false
} else {
empty.value = true
}
}
}
}
我正在使用导航在列表和项目之间导航
itemView.findNavController().navigate(R.id.action_listFragment_to_detailFragment)
由于以下代码,您每次都会重新创建回收列表 -
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupAdapter() //you are setting adapter every time view is getting created
setupObservers()
}
当您使用导航架构进行导航时,每次导航到目的地时,前一个片段将被停止()并在返回时重新创建。因为截至目前导航组件没有后台 issue
但是使用 ViewModel 的全部意义在于不保存片段状态并让 ViewModel 保留数据。您正在使用视图模型,但是您不能每次都在回收视图上设置适配器。
当您从视图模型中获取列表时,只需通知回收视图列表。
您永远不应该在 onResume()
等生命周期方法中重新加载数据 - 这就是为什么每次返回片段时数据都会重新加载。
相反,您应该在 ViewModel 的 init
块中只调用一次 fetchList()
- 这确保它只运行一次:
class ListViewModel : BaseViewModel() {
val listLive = MutableLiveData<List<Item>>()
init {
fetchList()
}
fun fetchList() {
dataLoading.value = true
ItemRepository.getInstance().getList() { isSuccess, response ->
dataLoading.value = false
if (isSuccess) {
listLive.value = response?.items
empty.value = false
} else {
empty.value = true
}
}
}
}
不清楚您的 getList()
方法是如何工作的。现在的写法对于单个回调通常是正确的。如果您的 getList()
实际上返回了一个值流,随着基础数据的变化继续传递回调,那么您必须确保在 onCleared()
中注销该回调(当 ViewModel 被销毁时的回调)。