So, I have a FragmentA. It contains a RecyclerView. It shows the list of items as expected at first. Now, when user clicks on one of the item, we navigate to FragmentB (FragmentA still in backstack). When user presses back, the backstack pops and now, we’re on FragmentA but, now, the RecyclerView is empty.
I’m using ViewModel, MutableStateFlow and StateFlow for all this.
Here’s the code:
ViewModel:
private val _uiData = MutableStateFlow(UIData())
val uiData = _uiData.asStateFlow()
private val _uiState = Channel<UIState>()
val uiState = _uiState.receiveAsFlow()
fun onUIEvent(uiEvent: UIEvent) = when (uiEvent) {
is UIEvent.LoadBondedDevices -> loadBondedDevices(uiEvent.bluetoothDevices)
}
private fun loadBondedDevices(bluetoothDevices: Set<BluetoothDevice?>) {
_uiState.trySend(UIState.Loading)
viewModelScope.launch {
val bondedDevices = bluetoothDevices.filterNotNull()
.map { bluetoothDevice: BluetoothDevice ->
BondedDevice(
bluetoothDevice.name,
bluetoothDevice.address
)
}
_uiData.update { uiData: UIData -> uiData.copy(bondedDevices = bondedDevices) }
_uiState.trySend(UIState.Idle)
}
}
Fragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Other code
viewBinding.recyclerView.adapter = bondedDevicesAdapter
lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
viewModel.uiData.collect { uiData: UIData ->
if (uiData.bondedDevices.isEmpty()) {
viewBinding.emptyMtv.visibility = View.VISIBLE
viewBinding.recyclerView.visibility = View.GONE
} else {
viewBinding.emptyMtv.visibility = View.GONE
viewBinding.recyclerView.visibility = View.VISIBLE
}
bondedDevicesAdapter.submitList(uiData.bondedDevices)
}
}
}
loadBondedDevices()
}
RecyclerViewAdapter is ListAdapter.
DiffItemCallbak:
class BondedDeviceDiffItemCallback : DiffUtil.ItemCallback<BondedDevice>() {
override fun areItemsTheSame(oldItem: BondedDevice, newItem: BondedDevice): Boolean {
return oldItem.address == newItem.address
}
override fun areContentsTheSame(oldItem: BondedDevice, newItem: BondedDevice): Boolean {
return oldItem.hashCode() == newItem.hashCode()
}
}