我有一个带有一个选项卡的ViewPager,该选项卡通过带有LiveData对象的ViewModel通过Room检索数据。
当我切换到任何选项卡并返回到该选项卡都显示项目列表时,一切正常,但是从后台进入时我不知道为什么,但是我收到的列表较少。
例如我第一次进入“列表片段”。
我从5个不同的实体中检索数据,并显示了5个列表项
转到背景并返回“列表片段”
4个列表有数据,但1个为空
转到背景并返回“列表片段”
3个列表有数据,但2个为空
...直到完全为空,然后切换选项卡,并充分填充列表
感谢您的帮助。
ViewModel
deferred
存储库getAllText()返回tagsDao.getTextList()
,Dao是:
class TagsViewModel(application: Application) : AndroidViewModel(application) {
private var repository: TagsRepository = TagsRepository(application)
private var listText: LiveData<List<Text>> = repository.getAllText()
private var listUrl: LiveData<List<Url>> = repository.getAllUrl()
private var listEmail: LiveData<List<Email>> = repository.getAllEmail()
private var listPhone: LiveData<List<Phone>> = repository.getAllPhone()
private var listLauncher: LiveData<List<Launcher>> = repository.getAllLauncher()
fun getData(): List<BaseTag>{
var allData= mutableListOf<BaseTag>()
if (listText.value != null){
listText.value!!.forEach {
allData.add(it)
}
}
if (listUrl.value != null){
listUrl.value!!.forEach {
allData.add(it)
}
}
if (listEmail.value != null){
listEmail.value!!.forEach {
allData.add(it)
}
}
if (listPhone.value != null){
listPhone.value!!.forEach {
allData.add(it)
}
}
if (listLauncher.value != null){
listLauncher.value!!.forEach {
allData.add(it)
}
}
return allData
}
//-------TEXT--------
fun insertText(text: Text) {
repository.insertText(text)
}
fun deleteTextByID(id: Int) {
repository.deleteTextByID(id)
}
fun getAllText(): LiveData<List<Text>> {
return listText
}
fun deleteAllText() {
repository.deleteAllText()
}
编辑
我将viewPager更改为不再重新创建片段,在onViewCreated中观察LiveData,清除onPause中的列表,并再次在onResume中设置数据,并添加viewLyfeCycleOwner
@Query("SELECT * FROM Text")
fun getTextList(): LiveData<List<Text>>
,它的工作原理与以前相同,当我从onResume中的背景回来时,viewModel总是返回的列表少了一点,而这完全是随机的,有时是textList,有时是emailList ...为什么它丢失了数据?我不知道为什么。
编辑2
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
v = inflater.inflate(R.layout.fragment_my_tags, container, false)
return v
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupUI()
}
private fun setupUI(){
val recyclerView = v.findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.setHasFixedSize(true)
recyclerView.adapter = adapter
tagsViewModel = ViewModelProviders.of(this).get(TagsViewModel::class.java)
getTags()
(activity as MainActivity).mToolbar.onMenuItemClick {
when (it!!.itemId){
R.id.btnDeleteAll -> toast("sort")
R.id.btnOrderBy -> tagsViewModel.deleteAll()
}
}
}
private fun getTags(){
tagsViewModel.getAllText().observe(viewLifecycleOwner,
Observer<List<Text>> { t -> adapter.setTags(t!!) })
tagsViewModel.getAllEmail().observe(viewLifecycleOwner,
Observer<List<Email>> { t -> adapter.setTags(t!!) })
tagsViewModel.getAllUrl().observe(viewLifecycleOwner,
Observer<List<Url>> { t -> adapter.setTags(t!!) })
tagsViewModel.getAllPhone().observe(viewLifecycleOwner,
Observer<List<Phone>> { t -> adapter.setTags(t!!) })
tagsViewModel.getAllLauncher().observe(viewLifecycleOwner,
Observer<List<Launcher>> { t -> adapter.setTags(t!!) })
}
override fun onPause() {
adapter.clear()
super.onPause()
}
override fun onResume() {
adapter.setTags(tagsViewModel.getData())
super.onResume()
}
答案 0 :(得分:1)
虽然我不确定为什么片段会以这种方式运行-可能需要看一下适配器的实现-但很少有事情引起我的注意:
observe
在onResume
中,但未在onPause
中清除
即使适配器在onPause
状态下被“清除”,观察者也不会。这意味着,每当片段到达背景然后再到前景时,该片段都会创建一组新的观察者集,而先前的观察者仍然活着并观察相同的LiveData
,因此由于这些重复的观察者而使得适配器的可预测性降低。 / p>
在观察this
时使用LiveData
LiveData
对象进入DESTROYED状态时, LifeCycle
个观察者将被取消订阅。这意味着为了避免观察者重复,应该在CREATED
状态之前订阅观察者,并且onCreate
方法是Activity
和Fragment
。如果您不喜欢这种行为,则需要传入另一个LifeCycleOwner
对象。
1。使用getViewLifecycleOwner()
在fragment.onCreate
中观察是非常不切实际的,因为片段的视图甚至还没有准备好。因此,Android具有一种称为getViewLifecycleOwner()
的便捷方法,可以在DESTROYED
阶段向onDestroyView()
发出信号,以便Fragment
可以在onCreateView()
阶段进行观察。您可以像这样使用它:
override fun onCreateView(...): View {
...
getTags()
...
return view
}
private fun getTags(){
tagsViewModel.getAllText().observe(getViewLifecycleOwner(),
Observer<List<Text>> { t -> adapter.setTags(t!!) })
tagsViewModel.getAllEmail().observe(getViewLifecycleOwner(),
Observer<List<Email>> { t -> adapter.setTags(t!!) })
tagsViewModel.getAllUrl().observe(getViewLifecycleOwner(),
Observer<List<Url>> { t -> adapter.setTags(t!!) })
tagsViewModel.getAllPhone().observe(getViewLifecycleOwner(),
Observer<List<Phone>> { t -> adapter.setTags(t!!) })
tagsViewModel.getAllLauncher().observe(getViewLifecycleOwner(),
Observer<List<Launcher>> { t -> adapter.setTags(t!!) })
}
2。使用自定义LifeCycleOwner
实施自定义LifeCycleOwner
。我认为这个article可以提供帮助。
Fragment
个生命周期,位于ViewPager
取决于ViewPager
的实现,仅通过切换选项卡,Fragment
不会进入onPause
-> onResume
状态。同样,标签之间的距离也很重要。例如,如果您切换到Fragment
旁边的标签,则可能不会“暂停”。尝试记录片段状态,以查看切换选项卡如何影响其生命周期。