【问题标题】:Fetch data from viewModel in fragment only once仅从片段中的 viewModel 获取数据一次
【发布时间】:2023-02-21 19:17:46
【问题描述】:

我只需要获取一次数据并避免在屏幕旋转时获取数据。

我的片段:

private var _binding: FragmentTopArticlesBinding? = null
    private val binding get() = _binding!!
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentTopArticlesBinding.inflate(inflater, container, false)
        getTopArticles()

        return binding.root
    }

观察状态的功能:

private fun getTopArticles() {
        var sortedList = emptyList<Article>()
        val adapter = ArticleAdapter(
            onArticleClicked = { title ->
                Toast.makeText(context, title, Toast.LENGTH_SHORT).show()
            }
        )
        binding.recyclerViewTop.layoutManager = LinearLayoutManager(context)
        binding.recyclerViewTop.adapter = adapter

        lifecycleScope.launch {
            viewModel.stateUI.collect { it ->
                when (it) {
                    is StateUI.Success -> {
                        it.articles.collect { articles ->
                            if (articles.isNotEmpty()) {
                                observeArticles(sharedViewModel, articles, adapter)

获取数据的函数:

private suspend fun observeArticles(
            sharedViewModel: SharedViewModel,
            articles: List<Article>,
            adapter: ArticleAdapter
        ) {
            binding.progressBar.visibility = View.GONE
            sharedViewModel.sortState.collect { sortState ->
                val sortedList = when (sortState) {
                    SortOrderState.Ascending -> {
                        sharedViewModel.sortArticles(articles)
                    }
                    SortOrderState.Descening -> {
                        sharedViewModel.sortArticles(articles)
    
                    }
    
                }
                adapter.submitList(sortedList)
    
                binding.recyclerViewTop.postDelayed({
                    binding.recyclerViewTop.scrollToPosition(0)
                }, 1000)
            }
        }

我的任务是在用户单击菜单项排序(asc 或 desc)时获取和排序 2 个片段的数据。问题是当我旋转屏幕时,这些函数获取数据但我只想在我第一次进入 Fragment 时执行一次。

我删除了这行代码:

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

因为我将无法使用 scrollToPosition。

编辑:

视图模型:

private val _cacheArticle = MutableStateFlow(emptyList<Article>())
    val cacheArticle = _cacheArticle.asStateFlow()


    init {
        viewModelScope.launch {

            if(cacheArticle.value.isEmpty()){
                val observeTopArticles = articleRepository.getTopArticles()
                _cacheArticle.value = observeTopArticles
                _stateUI.value = StateUI.Success(articles = observeTopArticles)
                Log.d(TAG, ": PULL")
            } else
            {
                Log.d(TAG, ": CACHE1")
                _stateUI.value = StateUI.Success(articles = _cacheArticle.value)
            }

        }

【问题讨论】:

  • 视图模型的发布代码/您如何获取数据。如果您只想获取一次数据,则不应使用流。 Small hack 可能会在收到第一个数据后调用取消。
  • 我删除了所有流但仍然从 api 获取数据,尝试使用一些本地 stateFlow 但它仍然不会存储数据并在我从 api 获取数据时使用它一次
  • 我刚刚重新阅读了您的问题。您不希望轮换获取数据。您正在使用 ViewModel。它不会。 ViewModel 在配置更改后仍然存在。
  • 那么可以在没有 cacheArticle 的情况下使用 viewModel 吗? observeTopArticles 从 api 获取数据,所以我认为当我旋转屏幕时它仍然获取数据。
  • 这不完全是我的意思。你在那里的代码,它不会在旋转时重新获取它。 ViewModels init 只会被调用一次——也就是说,如果您正确地创建了 viewModel

标签: android kotlin mvvm fragment viewmodel


【解决方案1】:

您可以像这样在 Fragment 中获取数据

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    if(savedInstanceState == null)
        viewModel.fetchData()
}

屏幕旋转和fragment重新创建后savedInstanceState不会为null,所以该方法只会在第一次创建fragment时调用一次。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多