Combining two flows of paging data before showing in UI

1k Views Asked by At

I have this recycler view that shows paginated data with a PagingDataAdapter. It works well when making a single request to the service but I sometimes need to make two requests to get old and new events and show both in my recycler view. Is there a way I can combine the two flows of paginated data before showing them to the user? As it is, if I make the two requests, only the last one remains because of the invalidate() in the submitData method.

This is the current implementation that doesn't work the way I need it to:

   private fun fetchEvents() {
       fetchEventsJob?.cancel()
       binding.cameraVmsEventsRecycler.adapter = null

       fetchEventsJob = lifecycleScope.launch {
           cameraViewModel.searchCameraEvents(
               cameraId = videoDetector.id,
               dateTo = if(eventsByDate) "" else dayPickerDateTo,
               pageSize = REQUEST_LIMIT
               cameraViewModel.filtersApplied
           ).collectLatest { eventsCollection ->
               val events = eventsCollection.map { event ->
                 
                   CameraEventModel.CameraEventItem(
                       VideoEventModel(
                           event.eventId,
                           event.faceId,
                           null,
                           event.state
                       )
                   )
               }.insertSeparators {
                       before: CameraEventModel.CameraEventItem?, after: CameraEventModel.CameraEventItem? ->
                   renderSeparators(before, after)
               }
               binding.cameraEventsRecycler.adapter = eventsAdapter
               eventsAdapter.submitData(events)
           }
       }
   }

Upong calling fetchEvents() with different parameters, only the last flow of data remains due to the submitData(). Is there a way I can manage to do what I want? I can't use Room in this project.

1

There are 1 best solutions below

4
Brian On

You are explicitly calling collectLatest: it cancels collection when new items emit. The effect is, if you suspend in the collector lambda before your call to submitData() you only get the last item from the flow.

If you want to use all items from searchCameraEvents you might need to use toList():

val flow = cameraViewModel.searchCameraEvents(/*...*/)
val eventsCollection: List<PagingData<List<Event>>> = flow.toList()
val events = eventsCollection
  // get list out of paging data
  .flatMap { it.data }
  // flatten list of lists
  .flatten()
  // map as needed
  .map { event ->
     CameraEventModel.CameraEventItem(/*...*/)
}

Mind, that you are handling paged data here. You want to make sure to keep a proper ordering. Also, if you retrieve more than one page from your flow, you're actually skipping the paging mechanism somehow. So you might also need to keep track of this in order not to produce duplicates in the UI.