androidkotlinandroid-recyclerviewandroid-listadapter

How can I refresh the data source of ListAdapter at once after I launch submitList in Android?


I use ListAdapter as the source of a RecyclerView, it will display a list of MVoice. The data source is mHomeViewModel.listVoiceBySort, it's LiveData<List<MVoice>>, you can see Code A.

After I added a record, mHomeViewModel.listVoiceBySort.observe will be launched, myAdapter.submitList(it) will be launched too.

But I found, the latest mHomeViewModel.listVoiceBySort isn't applied to ListAdapter, you can see Log A.

How can I refresh the data source of ListAdapter at once after I launch submitList ?

Log A

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

Code 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
    }
}

Added Content

To Tenfour04: Thanks!

The following Code B is how to get the LiveDate mHomeViewModel.listVoiceBySort.

Code 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() {
   ...
}

Solution

  • submitList() is asynchronous. Calling other methods on myAdapter right away after submitList() may not reflect the list that you just submitted.

    Instead, you could override onCurrentListChanged() and look at the adapter at that point.

    Or, just count the rows that you see on the screen. 😉