In particular use case I'm making a repository call to obtain data in form of Flow.
It's type is:
Flow<Resource<List<Location>>>
Where:
Resource is wrapper class:
sealed class Resource<T>(val data: T? = null, val message: String? = null) { class Loading<T>(data: T? = null): Resource<T>(data) class Success<T>(data: T?): Resource<T>(data) class Error<T>(message: String, data: T? = null): Resource<T>(data, message)}
Location is my data model class
Each location has it's own property like type. When user switch to section where type's Hotel, use case method is triggered, api call is made and I'm filtering list so that it contains only desirable items.
However the problem is filtering mechanims which doesn't work.
return repository.getLocations()
.onEach { result ->
if (result.data != null) {
when (locationType) {
is LocationType.All -> result.data
is LocationType.Hotel -> result.data.filter { it.type == "Hotel" }
is LocationType.Explore -> result.data.filter { it.type == "Explore" }
is LocationType.Active -> result.data.filter { it.type == "Active" }
is LocationType.Restaurant -> result.data.filter { it.type == "Restaurant" }
}
}
}
Final list isn't changed despite filtering with use ofonEach
UPDATE
The return type of repository call is:
Flow<Resource<List<Location>>>
CodePudding user response:
If you want to filter the result you should filter it directly . the onEach
is not needed here.
You can do it this way .
val result = repository.getLocations()
return if(result.data!=null){
result.data.filter { item ->
when (locationType) {
is LocationType.Hotel -> item.type == "Hotel"
is LocationType.Explore -> item.type == "Explore"
is LocationType.Active -> item.type == "Active"
is LocationType.Restaurant ->item.type == "Restaurant"
else -> true
}
}
}else{
emptyList()
}
this is just for explanation you can modify and make it more kotlinify
.
LocationType
is a constant here so you can directly do something like this you do not need a when
here.
val result = repository.getLocations()
return if(result.data!=null){
result.data.filter { item ->
item.type == locationType
}
}else{
emptyList()
}
CodePudding user response:
filter
doesn't filter a list in place. It returns a filtered copy of the list.
It also doesn't make sense to use onEach
. You are repeatedly redundantly filtering your same list as many times as it has items. And you are throwing away all those filtered copies since you do nothing with them. onEach
is for performing a side-effect action on each item and returning the original list.
You need to create your filtered copy one time. Then you can put that filtered copy back into a new Success
instance to return.
val result repository.getLocations()
if (result !is Success<List<Location>>) {
return result
}
val filteredData = result.data?.filter {
it.type == when (locationType) {
is LocationType.All -> it.type
is LocationType.Hotel -> "Hotel"
is LocationType.Explore -> "Explore"
is LocationType.Active -> "Active"
is LocationType.Restaurant -> "Restaurant"
}
}
return Success(data = filteredData)
Side note, you are missing the point of using a sealed class. Since you are putting all the possible properties in the parent class, there's no point in making it sealed and giving it children--it could just have one more property that indicates it represents loading, success, or error. Now you have to deal with nullable data
and error message
even if you've checked the child type. The whole point of using a sealed class vs. a single class would be to avoid having to make those nullable. Your parent class should have no properties defined. The Loading class doesn't need properties and can therefore be an object
. Your Success class can have a single non-nullable data
property, and the Error class can have a single non-nullable message
property. The Success and Error classes can be data
classes so they are more easily compared. It should look like this:
sealed class Resource<T> {
object Loading<T>: Resource<T>()
data class Success<T>(val data: T): Resource<T>()
data class Error<T>(message: String): Resource<T>()
}