我在 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 每次更新时都会给你新的实例)。
要解决这个问题,您需要比较的不是它们是否是同一实例,而是它们是否代表相同的对象。正如我所见,您的文章具有独特的网址。所以可以使用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/