Empty2k12 Empty2k12 - 28 days ago 6
Android Question

Grouping Model class into other Model with RxJava

I am working with the Android Room Persistence Library, which returns a Flowable of List of MyModel (

Flowable<List<MyModel>>
).
MyModel
has the function
getMonth
which returns a integer.

I am trying to group MyModel's into MyModelWrapper which is a wrapper class for a List of MyModel and the integer (
MyModelWrapper(int month, List<MyModel>)
).

The code should group the List of
MyModel
MyModel(0)
,
MyModel(0)
,
MyModel(1)
,
MyModel(2)
into a List of
MyModelWrapper
MyModelWrapper(0, List(MyModel(0), MyModel(0))
,
MyModelWrapper(1, List(MyModel(1))
and
MyModelWrapper(2, List(MyModel(2))
.

My current code which is not using RxJava

List<MyModel> models = database.myModelDao().getMyModels();

Map<Integer, List<MyModel>> orderedData = new HashMap<>();
for(MyModel model : models) {
if(orderedData.get(model.getMonth()) == null) {
orderedData.put(model.getMonth(), new ArrayList<MyModel>());
}
orderedData.get(model.getMonth()).add(model);
}

final ArrayList<MyModelWrapper> recordedModels = new ArrayList<>();
for (Map.Entry<Integer, List<MyModel>> cursor : recordedModels.entrySet()) {
List<MyModel> myModelRecords = cursor.getValue();
MyModelWrapper modelWrapper = new MyModelWrapper()
.setMyModels(myModelRecords)
.setMonth(cursor.getKey());
recordedModels.add(modelWrapper);
}

return recordedModels;


How would I RxIfy this?

I tried getting the first Element from the
Flowable
with
first()
, the
groupBy()
my key but that is returning a
GroupedObservable
which would somehow be turned into a list, then transformed into a List to be converted to MyModelWrapper.

Any help is appreciated!




Solution I ended up using:

getMyModelsFlowable()
.flatMapIterable(new Function<List<MyModel>, Iterable<MyModel>>() {
@Override
public Iterable<MyModel> apply(List<MyModel> models) throws Exception {
return models;
}
}).groupBy(new Function<MyModel, Integer>() {
@Override
public Integer apply(MyModel model) throws Exception {
return model.getMonth();
}
}).flatMapSingle(new Function<GroupedFlowable<Integer, MyModel>, SingleSource<MyModelWrapper>>() {
@Override
public SingleSource<MyModelWrapper> apply(final GroupedFlowable<Integer, MyModel> group) throws Exception {
return group.toList().map(new Function<List<MyModel>, MyModelWrapper>() {
@Override
public MyModelWrapper apply(List<MyModel> models) throws Exception {
return new MyModelWrapper()
.setMyModels(models)
.setMonth(group.getKey());
}
});
}
});

Answer Source

Your approach with GroupedFlowable is correct. Consider this test snippet

@Test
fun modelWrap() {
    val data = Flowable.just(listOf(
            Model(1, "1"), 
            Model(2, "2"), 
            Model(1, "3"), 
            Model(3, "4")))
    val modelsByMonth = data.flatMapIterable { it }.groupBy { it.month }
    val wrappedModels = modelsByMonth
            .flatMapSingle { group ->
                group.toList().map { modelsList -> WrappedModel(group.key, modelsList) }
            }
    val wrappedModelsList = wrappedModels.toList()
    val wrappedModelsVal = wrappedModelsList.blockingGet()
    Assert.assertNotNull(wrappedModelsVal)
    Assert.assertEquals(3, wrappedModelsVal.size)

}

data class Model(val month: Int, val data: String)
data class WrappedModel(val month: Int?, val data: List<Model>)

It produces output

[WrappedModel(month=1, data=[Model(month=1, data=1), Model(month=1, data=3)]), WrappedModel(month=2, data=[Model(month=2, data=2)]), WrappedModel(month=3, data=[Model(month=3, data=4)])]

I think you are mostly interested how wrappedModels val is constructed