android - 从数据库加载数据时 RecyclerView 闪烁

标签 android android-recyclerview

我在 Github 中有以下项目:https://github.com/AliRezaeiii/News-Cache

首先,我在 fragment 中加载数据,显示数据库中的数据,然后开始从 API 加载数据。一旦从 API 加载完成,我就会更新数据库,并且 Fragment 中的 recyclerView 也会更新。

override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel.news.observe(viewLifecycleOwner, Observer<List<Article>> { articles ->
            articles?.apply {
                viewModelAdapter.submitList(articles)
            }
        })
    }

这是我的 View 模型:

class NewsViewModel(application: Application) : AndroidViewModel(application) {

    private val viewModelJob = SupervisorJob()

    private val viewModelScope = CoroutineScope(viewModelJob + Dispatchers.Main)

    private val database = getDatabase(application)
    private val articleRepository = ArticlesRepository(database)

    init {
        viewModelScope.launch {
            articleRepository.refreshArticles()
        }
    }

    private val _news = articleRepository.articles
    val news: LiveData<List<Article>>
        get() = _news
}

这是我的 Repository 类:

class ArticlesRepository(private val database: NewsDatabase) {

   /**
     * A list of articles that can be shown on the screen.
     */
    val articles: LiveData<List<Article>> =
        Transformations.map(database.newsDao.getArticles()) {
            it.asDomainModel()
        }

    /**
     * Refresh the articles stored in the offline cache.
     *
     * This function uses the IO dispatcher to ensure the database insert database operation
     * happens on the IO dispatcher. By switching to the IO dispatcher using `withContext` this
     * function is now safe to call from any thread including the Main thread.
     *
     * To actually load the articles for use, observe [articles]
     */
    suspend fun refreshArticles() {
        withContext(Dispatchers.IO) {
            try {
                val news = Network.news.getNews().await()
                database.newsDao.insertAll(*news.asDatabaseModel())
            } catch (exception: IOException) {
                Timber.e(exception)
            }
        }
    }
}

这是我的适配器:

class NewsAdapter(val callback: OnClickListener) : ListAdapter<Article, NewsAdapter.NewsViewHolder>(DiffCallback) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = NewsViewHolder.from(parent)

    override fun onBindViewHolder(holder: NewsViewHolder, position: Int) {
        holder.bind(getItem(position), callback)
    }

    /**
     * Allows the RecyclerView to determine which items have changed when the [List] of [Article]
     * has been updated.
     */
    companion object DiffCallback : DiffUtil.ItemCallback<Article>() {
        override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
            return oldItem == newItem
        }

        override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
            return oldItem.url == newItem.url
        }
    }
}

当我启动应用程序(创建一个新的应用程序实例)并且没有来自 API 的新数据时,RecyclerView 闪烁。有什么办法可以解决吗?

最佳答案

你的问题是 DiffCallback 的错误实现,当 areItemsTheSame 被调用时总是返回 false,即使比较的实例代表相同的对象(因为 db 每次更新时都会给你新的实例)。

p>

要解决这个问题,您需要比较的不是它们是否是同一实例,而是它们是否代表相同的对象。正如我所见,您的文章具有独特的网址。所以可以使用aricle.url或者引入id字段使用id。

    companion object DiffCallback : DiffUtil.ItemCallback<Article>() {
        override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
            return oldItem.url == newItem.url
        }

        override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
            return oldItem == newItem
        }
    }

关于android - 从数据库加载数据时 RecyclerView 闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57686798/

相关文章:

java - 从 RecyclerView 中消失的数据

java - 更改微调项数据时更新 recyclerview 单行数据

Android RecyclerView 添加分页

Android - 顶部带有圆角的可绘制对象仅在 v14 以下不起作用

android - 找不到符号变量 FLAG_ACTIVITY_CLEAR_TASK

Android 屏幕录制操作方法 - 横向录制、录制的视频以全屏与部分屏幕播放

android - ADB 安装失败并显示 INSTALL_FAILED_TEST_ONLY

java - 如何在Tomcat上实现Java Socket通信

android - 单击 RecyclerView 空白区域

java - fragment 显示但回收器 View 不显示