【问题标题】:How can I refresh the data source of ListAdapter at once after I launch submitList in Android?如何在 Android 中启动 submitList 后立即刷新 ListAdapter 的数据源?
【发布时间】:2021-03-28 05:15:01
【问题描述】:

我使用 ListAdapter 作为 RecyclerView 的来源,它将显示MVoice 的列表。数据源是mHomeViewModel.listVoiceBySort,是LiveData<List<MVoice>>,可以看代码A。

我添加记录后,mHomeViewModel.listVoiceBySort.observe 会启动,myAdapter.submitList(it) 也会启动。

但是我发现,最新的mHomeViewModel.listVoiceBySort并没有应用到ListAdapter,你可以看Log A。

如何在启动 submitList 后立即刷新 ListAdapter 的数据源?

日志 A

E/My: itemCount: 13 it: 14 CurrentList:13

代码 A

binding.recyclerViewVoice.adapter = myAdapter
mHomeViewModel.listVoiceBySort.observe(this.viewLifecycleOwner) {
   myAdapter.submitList(it)
   Log.e("My","itemCount: "+myAdapter.itemCount+ " it: "+it.size+ " CurrentList:"+myAdapter.currentList.size)

}

class VoiceAdapters (private val aHomeViewModel: HomeViewModel, private val mPlay: PlayInterface):
        ListAdapter<MVoice, VoiceAdapters.VoiceViewHolder>(MVoiceDiffCallback()) {

    private lateinit var mContext: Context
    private lateinit var mLifecycleOwner:LifecycleOwner

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VoiceViewHolder {
        mContext = parent.context
        mLifecycleOwner = mContext as LifecycleOwner

        return VoiceViewHolder(
            LayoutVoiceItemBinding.inflate(LayoutInflater.from(parent.context), parent, false).also {              
               it.lifecycleOwner = mLifecycleOwner
               it.aHomeViewModel = aHomeViewModel
            }
        )
    }

    override fun onBindViewHolder(holder: VoiceViewHolder, position: Int) {
        val inputMVoice = getItem(position)
        holder.bind(inputMVoice)
    }

   
    inner class VoiceViewHolder (private val binding: LayoutVoiceItemBinding):
          RecyclerView.ViewHolder(binding.root) {
       
        fun bind(inputMVoice: MVoice) {                        
            binding.amVoice = inputMVoice          
            binding.executePendingBindings()
        }
    }

}


class MVoiceDiffCallback : DiffUtil.ItemCallback<MVoice>() {
    override fun areItemsTheSame(oldItem: MVoice, newItem: MVoice): Boolean {
        return oldItem.id == newItem.id
    }

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

添加内容

致 Tenfour04:谢谢!

以下代码 B 是如何获取 LiveDate mHomeViewModel.listVoiceBySort

代码 B

class HomeViewModel(val mApplication: Application, private val mDBVoiceRepository: DBVoiceRepository) : AndroidViewModel(mApplication) {

    private val _listVoiceBySort=_sortBy.switchMap {
        mDBVoiceRepository.listVoiceBySort(it)
    }

    val listVoiceBySort: LiveData<List<MVoice>> =_listVoiceBySort
    ...
}

class DBVoiceRepository private constructor(private val mDBVoiceDao: DBVoiceDao){

    private val _isHaveRecord= MutableLiveData<Boolean>(false)
    val isHaveRecord:LiveData<Boolean> =_isHaveRecord

    fun listVoiceBySort(aSortBy: ESortBy): LiveData<List<MVoice>> {
        var query=when (aSortBy){
            ESortBy.StartPriority ->
               "SELECT * FROM voice_table ORDER BY starred desc, createdDate desc"
            ESortBy.DateDesc ->
               "SELECT * FROM voice_table ORDER BY createdDate desc"
            ESortBy.DateAsc ->
               "SELECT * FROM voice_table ORDER BY createdDate"
            ESortBy.TitleDesc ->
               "SELECT * FROM voice_table ORDER BY title desc"
            ESortBy.TitleAsc ->
               "SELECT * FROM voice_table ORDER BY title"
        }
        return mDBVoiceDao.runtimeQuery(SimpleSQLiteQuery(query)).map {
            _isHaveRecord.value =!it.isNullOrEmpty()
            it
        }
    }
    ...
}

@Dao
interface DBVoiceDao{   
   @RawQuery(observedEntities = [MVoice::class])
   fun  runtimeQuery(sortQuery: SupportSQLiteQuery): LiveData<List<MVoice>>
   ...
}


abstract class DBVoiceDatabase : RoomDatabase() {
   ...
}

【问题讨论】:

  • 您能说明如何更新 LiveData 中的值吗?
  • 谢谢!添加记录后我没有做更新LiveDatemHomeViewModel.listVoiceBySort的操作,好像系统自动更新了LiveData。
  • 实时数据实例从何而来?我问的原因是,如果你有一个列表的 LiveData,它不会向现有观察者报告基础列表的更改,除非你手动触发它。
  • 谢谢!我从 ViewModel 获得 LiveDate mHomeViewModel.listVoiceBySort,它是一个使用 @DAO 的带有 Room 的 SQLite 表。
  • 是的,但是你能显示代码吗?你调用的 DAO 函数是什么?它返回 Flow 或 LiveData 还是仅返回一个列表?如何将它返回的内容转换为 LiveData?

标签: android kotlin android-recyclerview android-listadapter


【解决方案1】:

你应该改变你的提交代码

mHomeViewModel.listVoiceBySort.observe(this.viewLifecycleOwner) {
   (binding.recyclerViewVoice.adapter as YourAdapter).submitList(it.map { it.copy() })
   Log.e("My","itemCount: "+myAdapter.itemCount+ " it: "+it.size+ " CurrentList:"+myAdapter.currentList.size)

}

您将列表引用提交给适配器,并且当发生更改时,适配器内部已经发生了更改,而 diffutil 找不到任何差异。您可以在提交时通过复制列表项来解决该问题。

【讨论】:

  • 谢谢!但是当我使用您的代码添加记录时,我得到的结果与“Log A”相同。
  • 编辑了我的答案你能再检查一遍吗?
  • 谢谢!当我使用更新的代码添加记录时,我仍然得到与“Log A”相同的结果
【解决方案2】:

submitList() 是异步的。在submitList() 之后立即在myAdapter 上调用其他方法可能不会反映您刚刚提交的列表。

相反,您可以override onCurrentListChanged() 并在此时查看适配器。

或者,只计算您在屏幕上看到的行数。 ?

【讨论】:

  • 谢谢!但是myAdapter.onCurrentListChanged(){previousList, currentList -&gt; ...} 不起作用
  • @HelloCW:我不知道在这种情况下“不起作用”是什么意思。无论如何,您现有的日志记录也无法正常工作。如果您需要能够同步更新列表内容,请不要使用ListAdapter。相反,请创建自己的 RecyclerView.Adapter,它的工作不使用后台线程。
猜你喜欢
  • 2022-01-03
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 2022-06-15
  • 2015-07-16
  • 2021-10-12
  • 2019-01-17
相关资源
最近更新 更多