实时数据中的 Observables 更新在片段中不起作用

Posted

技术标签:

【中文标题】实时数据中的 Observables 更新在片段中不起作用【英文标题】:Observables updates in the live data dont working in fragment 【发布时间】:2021-06-25 07:04:46 【问题描述】:

我有一个片段实例化一个由koin注入的视图模型,问题是,在视图模型的postValue()动作之后,观察到的属性之一没有在片段中激发,它根本没有进入方法片段中,即使它已被更新。

片段:

class ListFragment : Fragment() 

private lateinit var adapter: PostAdapter
private val viewModel: PostsViewModel by viewModel()
private var _binding: ListFragmentBinding? = null
private var defaultTopic = "news"
private var afterPage: String = ""

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
): View? 
    return inflater.inflate(R.layout.list_fragment, container, false)


override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setHasOptionsMenu(true)


override fun onViewCreated(view: View, savedInstanceState: Bundle?) 
    super.onViewCreated(view, savedInstanceState)
    _binding = ListFragmentBinding.bind(view)

    adapter = PostAdapter(mutableListOf(), requireContext()) 
        val action = ListFragmentDirections.openDetailsFragment(it)
        findNavController().navigate(action)
    

    _binding?.let
        val llm = LinearLayoutManager(requireContext())
        it.recyclerviewPosts.layoutManager = llm
        it.recyclerviewPosts.adapter = adapter

        recyclerViewListenerSetup(it, llm)
    
    setupObservers()



private fun recyclerViewListenerSetup(it: ListFragmentBinding, llm: LinearLayoutManager) 
    it.recyclerviewPosts.addOnScrollListener(object : RecyclerView.OnScrollListener() 
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) 
            super.onScrolled(recyclerView, dx, dy)
            val visibleItemCount: Int = llm.childCount
            val totalItemCount: Int = llm.itemCount
            val firstVisibleItemPosition: Int = llm.findFirstVisibleItemPosition()

            if((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
                    && firstVisibleItemPosition >= 0) 
                viewModel.getNextPage(defaultTopic, afterPage)
            
        
    )


private fun setupObservers()
    viewModel.getPostList(defaultTopic)
    viewModel.posts.observe(this as LifecycleOwner,  posts ->
        if (posts.isSuccess && posts.getOrNull() != null) 
            adapter.updateList(posts.getOrNull()!! as MutableList<PostsDTO>)
            afterPage = posts.getOrNull()!![0].after
            showList()
         else 
            showError()
        
    )
    viewModel.loading.observe(this as LifecycleOwner, 
        if (it) 
            showLoading()
         else 
            hideLoading()
        
    )
    viewModel.next.observe(this as LifecycleOwner, 
        if (it.isSuccess && it.getOrNull() != null) 
            adapter.addList(it.getOrNull() as MutableList<PostsDTO>)
            afterPage = it.getOrNull()!![0].after
        
    )


private fun showList()
    _binding?.let 
        it.recyclerviewPosts.visibility = VISIBLE
    


private fun showLoading()
    _binding?.let 
        it.loading.visibility = VISIBLE
        it.containerError.root.visibility = GONE
        it.recyclerviewPosts.visibility = GONE
    


private fun hideLoading()
    _binding?.let 
        it.loading.visibility = GONE
    


private fun showError() 
    _binding?.let 
        it.containerError.root.visibility = VISIBLE
        it.recyclerviewPosts.visibility = GONE
    


override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) 
    inflater.inflate(R.menu.menu_main, menu)
    val searchItem = menu.findItem(R.id.action_search)
    val searchManager =
        requireActivity().getSystemService(Context.SEARCH_SERVICE) as SearchManager
    val searchView = searchItem.actionView as SearchView
    searchView.setSearchableInfo(searchManager.getSearchableInfo(activity?.componentName))

    searchView.apply 
        queryHint = "Search SubReddit"
        setOnQueryTextListener(object : SearchView.OnQueryTextListener 
            override fun onQueryTextSubmit(query: String?): Boolean 
                defaultTopic = query!!
                viewModel.getPostList(defaultTopic)
                return false
            

            override fun onQueryTextChange(newText: String?): Boolean 
                return true
            
        )
    
    super.onCreateOptionsMenu(menu, inflater)



我尝试在recyclerView滚动时调用viewmodel方法更新显示的列表。

视图模型:

class PostsViewModel(private val repository: PostsRepository) : ViewModel()

private val _posts = MutableLiveData<Result<List<PostsDTO>>>()
val posts: LiveData<Result<List<PostsDTO>>>
    get() =_posts

private val _loading = MutableLiveData<Boolean>()
val loading: LiveData<Boolean>
    get() = _loading

private val _next = MutableLiveData<Result<List<PostsDTO>>>()
val next: LiveData<Result<List<PostsDTO>>>
    get() =_posts

fun getPostList(q: String)
    viewModelScope.launch 
        _loading.postValue(true)
        repository.fetchPosts(q)
            .collect 
                _posts.value = it
            
        _loading.postValue(false)
    


fun getNextPage(topic: String, afterPage: String) 
    viewModelScope.launch 
        repository.fetchNextPage(topic, afterPage)
                .collect
                    _next.postValue(it)
                
    


 

这种情况下next方法的请求结果更新完viewmodel后,viewmodel.next.observer()中就不会激发fragment

【问题讨论】:

这可能是视图模型的生命周期所有者的原因,我无法从您的代码中弄清楚。您可以将活动作为 viewmodel 生命周期所有者仅用于测试。 【参考方案1】:

奥帕!经过单元测试后,我能够找出问题所在,问题是 ctrl + v,下一个属性,它返回的是 _post 属性而不是 _next 属性,因此视图没有收到更新通知。 更正的修正是在viewmodel中,改变下一个变量的get方法:

private val _next = MutableLiveData<Result<List<PostsDTO>>>()
val next: LiveData<Result<List<PostsDTO>>>
    get() =_next

【讨论】:

以上是关于实时数据中的 Observables 更新在片段中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2 “实时”更新对象。

当 Firestore 字段更新时,Observables 会重新查询所有数据吗?

从数据库成功检索数据后,医疗 ID 片段未更新

如何使用实时数据从 RecyclerView 中删除项目?

想要使用 SharePreferences 更新第二个片段中的数据,但第二个片段没有更新

Angular2/4:实时刷新数据