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

jfewjypa  于 2023-06-06  发布在  Kotlin
关注(0)|答案(3)|浏览(399)

我使用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
    }
}

新增内容

致天福04:谢谢!
下面的代码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() {
   ...
}
c90pui9n

c90pui9n1#

submitList()是异步的在submitList()之后立即调用myAdapter上的其他方法可能无法反映您刚刚提交的列表。
相反,您可以覆盖onCurrentListChanged()并查看此时的适配器。
或者,只需计算您在屏幕上看到的行。😉

jjjwad0x

jjjwad0x2#

您应该更改提交代码,如

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)

}

你把你的列表引用提交给adapter,当有什么变化的时候,adapter内部已经有了变化,diffutil找不到任何区别。您可以通过在提交时复制列表项来修复该问题。

yrwegjxp

yrwegjxp3#

如果你想使用ListAdapter,但将submitList()改为同步提交列表更新而不是异步,你可以创建自己的backing list并覆盖一些方法,如下所示:

inner class MyListAdapter() : ListAdapter<MyListItem, MyViewHolder>(MyDiffUtil) {
    private var currentList: List<MyListItem> = listOf()
    override fun getCurrentList(): List<MyListItem> = currentList
    override fun getItemCount(): Int = currentList.size
    override fun getItem(position: Int) = currentList[position]

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val binding = MyItemBinding.inflate(layoutInflater, parent, false)
        return MyViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ProjectViewHolder, position: Int) {
        holder.bind(currentList[position])
    }

    override fun submitList(list: List<MyListItem>?) {
        submitList(list, null)
    }

    override fun submitList(list: List<MyListItem>?, commitCallback: Runnable?) {
        requireNotNull(list)

        //Your implementation of DiffUtil goes here. It will probably be the same as
        //MyDiffUtil in the first line of this code snippet.
        val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
            override fun getOldListSize() = currentList.size

            override fun getNewListSize() = list.size

            override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
                currentList[oldItemPosition].myItemId == list[newItemPosition].myItemId

            override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
                false

            override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int) =
                "Rebind-Payload"
        })

        diff.dispatchUpdatesTo(this)
        currentList = list.toMutableList()

        commitCallback?.run()
    }
}

注意:这是一个内部类,所以我们可以在使用它的Fragment上调用layoutInflater

相关问题