Android mediator live data combine 2 live data into one stream and one trigger

918 Views Asked by At

I have 2 live data, I add them as sources to a mediator live data, I expose this from a view model for a fragment to observe.

When either of the live data changes it triggers the onChanged method of the mediator live data, which means my observer gets triggered twice, what I want is to combine the two and observe just one stream that only triggers once, is there something I'm missing or do I need to roll my own method for this? currently I do this, which triggers twice

SOME CODE REMOVED FOR BREVITY

public CardViewModel(@NonNull Application application , int clicks, String[] cardArgs){
    sentenceRepository = new SentenceRepository(application);
    cards = Transformations.switchMap(search, mySearch -> sentenceRepository.searchLiveCardListByWordTypeAndWordDescriptionAndSearchWord(cardArgs[0],cardArgs[1],mySearch));
    groupRepository = new GroupRepository(application);
    groups = groupRepository.getGroupsByWordDescriptionAndWordType(cardArgs[0],cardArgs[1]);
    sentencesAndGroups = new MediatorLiveData<>();

    sentencesAndGroups.addSource(cards, sentences -> {
        Log.d(TAG,"addSource cards");
        sentencesAndGroups.setValue(combineLatest(sentences, groups.getValue()));
    });

    sentencesAndGroups.addSource(groups, groupsWithSentences -> {
        Log.d(TAG,"addSource groups");
        sentencesAndGroups.setValue(combineLatest(cards.getValue(), groupsWithSentences));
    });

}

private List<Visitable> combineLatest(List<Sentence> sentenceList, List<GroupsWithSentences> groupsWithSentences) {
    List<Visitable> visitableList = new ArrayList<>();
    if (sentenceList != null){
        visitableList.addAll(sentenceList);
    }
    if (groupsWithSentences != null){
        visitableList.addAll(groupsWithSentences);
    }
    return visitableList;
}

any help?

1

There are 1 best solutions below

3
On

You can use a BiFunction. In my project I have a class which contains this:

public class MultipleLiveDataTransformation {
    @MainThread
    public static <X, Y, O> LiveData<O> biMap(LiveData<X> data1, LiveData<Y> data2, final BiFunction<X, Y, O> biFun) {
        final MediatorLiveData<O> result = new MediatorLiveData<>();
        result.addSource(data1, x -> result.setValue(biFun.apply(x, data2.getValue())));
        result.addSource(data2, y -> result.setValue(biFun.apply(data1.getValue(), y)));

        return result;
    }
}

You can use it like this:

public LiveData<Visitable> getVisitables() {
    return MultipleLiveDataTransformation.biMap(groups, sentences, (gro, sen) -> {
        List<Visitable> visitableList = new ArrayList<>();
        if (gro != null) {
            visitableList.addAll(gro);
        }
        if (sen != null) {
            visitableList.addAll(sen);
        }
        return visitableList;
    });
}

I do not fully understand what lists you have and what you want to observe. The example I gave here can observe two LiveData objects and triggers when one of them needs to update. It will always give you the most up to date version of the Visitable objects.

If I don't understand the problem, can you explain what LiveData objects need to be combined and what the result needs to be?

In the case, that an extra LiveData object needs to be observed in the MultipleDataTransformation, it is possible to make a triMap.

Edit: You can try this:

public LiveData<Visitable> getVisitables() {
    return MultipleLiveDataTransformation.biMap(groups, sentences, (gro, sen) -> {
        List<Visitable> visitableList = new ArrayList<>();
        if (gro != null && !gro.isEmpty() && sen != null && !sen.isEmpty()) {
            visitableList.addAll(gro);
            visitableList.addAll(sen);
        }
        return visitableList;
    });
}