Home > Enterprise >  filter flowable list of object by category and group into another list of object in flow
filter flowable list of object by category and group into another list of object in flow

Time:11-12

is it possible to filter and group Flow<List<Object A>> by categories.

i found issue quite similar here , but no luck :(

here i'm sharing my approach which i tried,

code inside viewModel :

class HomeViewModel: ViewModel() {

 data class Car(val id: Int, val name: String, val category: Int)
 data class CarsByCategory(val categoryId:Int, val categoryName: String, val carList: List<Car>)

    private val categoryList =
        mapOf<Int, String>(1 to "Audi", 2 to "BMW", 3 to "Chevrolet", 4 to "Dodge", 5 to "Others")

    private val mutableCarList: MutableList<CarsByCategory> = mutableListOf()
    private val _mutableStateFlowCarList: MutableStateFlow<List<CarsByCategory>> = MutableStateFlow(emptyList())
    
    val filteredCarList: StateFlow<List<CarsByCategory>> = _mutableStateFlowCarList
    
    private fun getAllCarsAsFlow(): Flow<List<Car>> {
        val cars = listOf(
            Car(id = 1, name = "A1", category = 1),
            Car(id = 1, name = "A2", category = 1),
            Car(id = 1, name = "BMW X1", category = 2),
            Car(id = 1, name = "BMW X7", category = 2),
            Car(id = 1, name = "M Roadster", category = 2),
            Car(id = 1, name = "Bolt EUV", category = 3),
            Car(id = 1, name = "Blazer", category = 3),
            Car(id = 1, name = "Challenger", category = 4),
            Car(id = 1, name = "Neon", category = 4),
            Car(id = 1, name = "Frontier", category = 5)
        )
        return flowOf(cars)
    }
  
   private fun filterCarByCategory(){
        getAllCarsAsFlow().map { carList ->
            for (key in categoryList.keys) {
                val filteredList = carList.filter { car -> car.category == key }
                mutableCarList.add(
                    CarsByCategory(
                        categoryId = key,
                         categoryName= categories.getValue(key),
                        carList = filteredList
                    )
                )
            }
            _mutableStateFlowCarList.value = mutableCarList.toList()
        }
    }

    init {
        filterCarByCategory()
    }
}

code in fragment:

  ....

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

        lifecycleScope.launchWhenStarted {
            homeViewModel.filteredCarList.collect {
                Log.d(TAG, "onViewCreated: ${it.size}")
//                here getting car list size is 0
            }
        }
    }

  ...

i don't know is it right approach or not , please let me know how to solve this problem using flow

CodePudding user response:

A flow doesn't emit any value until it is collected. So you need to collect your flow:

private fun filterCarByCategory(){
    viewModelScope.launch {
        getAllCarsAsFlow().collect { carList ->
            // Rest everything same
        }
    }
}

Edit: If the sole purpose of _mutableStateFlowCarList is to provide data to UI, you need not use a StateFlow here, just a normal Flow would do the job.

val filteredCarList = getAllCarsAsFlow().map { carList ->
    categoryList.map { (id, name) ->
        CarsByCategory (
            categoryId = id,
            categoryName = name,
            carList = carList.filter { car -> car.category == id }
        )
    }
}
  • Related