---
title: "LiveData to the next level with MediatorLiveData and Transformations"
description: "An introduction to MediatorLiveData and Transformations to build reactive patterns with LiveData."
canonical: https://oozou.com/blog/livedata-to-the-next-level-with-mediatorlivedata-and-transformations-31
locale: en
date: 2018-12-07
author: "OOZOU Team"
---

# LiveData to the next level with MediatorLiveData and Transformations

> An introduction to MediatorLiveData and Transformations to build reactive patterns with LiveData.

Published: 2018-12-07 · Author: OOZOU Team (Engineering) · 4 min read

**MediatorLiveData**

From its explanation, it is a subclass of liveData which can ‘observe’ other LiveData and trigger onChanged() method when observed LiveData’s value is changed.

```
LiveData<String> source = ....; //
final MediatorLiveData<String> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String x) {
                // do something here 
            }
        });
lang-java
```

From the sample code above, when **_source’s value_** is changed, the **_onChanged_** method of **Observer** will be triggered.
Transformations**

This class is way more like an utilisation of MediatorLiveData. It contains only 2 methods which are map() and switchMap()

```
@MainThread
    public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,
            @NonNull final Function<X, Y> func) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) {
                result.setValue(func.apply(x));
            }
        });
        return result;
    }

   @MainThread
    public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger,
            @NonNull final Function<X, LiveData<Y>> func) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(trigger, new Observer<X>() {
            LiveData<Y> mSource;

            @Override
            public void onChanged(@Nullable X x) {
                LiveData<Y> newLiveData = func.apply(x);
                if (mSource == newLiveData) {
                    return;
                }
                if (mSource != null) {
                    result.removeSource(mSource);
                }
                mSource = newLiveData;
                if (mSource != null) {
                    result.addSource(mSource, new Observer<Y>() {
                        @Override
                        public void onChanged(@Nullable Y y) {
                            result.setValue(y);
                        }
                    });
                }
            }
        });
        return result;
    }
lang-java
```

These 2 methods doing the same thing which apply a function on the value stored in the LiveData object, and propagates the result downstream but the **switchMap(), the function that passed in must return a LiveData object.**

I’ve created a sample project [here](https://github.com/jutikorn/TodoSameple). You can take a look and stay with me to let me explain how the code works.

I use [https://jsonplaceholder.typicode.com/](https://jsonplaceholder.typicode.com/) as a test api with _/todos/1_ endpoint. There is a created model name **Todo** to match with the response

```
import com.google.gson.annotations.SerializedName

// https://jsonplaceholder.typicode.com/todo/1
class Todo(
    @SerializedName("userId") val userId: Int,
    @SerializedName("id") val id: Int,
    @SerializedName("title") val title: String,
    @SerializedName("completed") val completed: Boolean
)
lang-kotlin
```

There are 2 more classes for handling responses from api.

```
import android.arch.lifecycle.LiveData

data class ResponseError(val code: Int? = null, val messages: String? = null)

data class ResponseResult<T>(val data: LiveData<T>, val error: LiveData<ResponseError>)
lang-kotlin
```

The ResponseResult will have 2 properties, both are a LiveData, one is for the response, the other one is for the error (ResponseError).

According to the Google suggestion, I made a repository module with will take a responsibility to fetch a data from network. In this module, I did some trick with ResponseResult:

```
class TodoRepository(private val api: TodoApi) {

    fun getTodos(): ResponseResult<Todo> {
        val data = MutableLiveData<Todo>()
        val error = MutableLiveData<ResponseError>()
        api.getTodos().enqueue(object : Callback<Todo> {
            override fun onResponse(call: Call<Todo>, response: Response<Todo>) {
                if (response.isSuccessful) {
                    data.value = response.body()
                } else {
                    error.value = ResponseError(response.code(), response.errorBody()?.string())
                }
            }

            override fun onFailure(call: Call<Todo>, t: Throwable) {
                error.value = ResponseError()
            }
        })
        return ResponseResult(data, error)
    }
}
lang-kotlin
```

The function getTodos() will return `ResponseResult<Todo>`, its 2 properties, _data’s value_ will be updated when response is finished, and _error’s value_ will be updated when error happened.

By following the SOLID guideline, I keep my Usecase class so simple.

```
class GetTodoUsecases(private val repository: TodoRepository) {

    operator fun invoke() = repository.getTodos()
}
lang-kotlin
```
Chaining LiveData**

Let’s have a look at my ViewModel and Fragment class:

```
class MainFragment: Fragment(){
    ...
    ...
    ...
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel._onActivityCreated.call()
    }
    ...
    ...
    ...
}

class MainViewModel(private val getTodoUsecase: GetTodoUsecases) : ViewModel() {

    val _onActivityCreated = SingleLiveEvent<Any>()

    private val responseResult: LiveData<ResponseResult<Todo>> = Transformations.map(_onActivityCreated) {
        getTodoUsecase()
    }

    val todoResult: LiveData<Todo> = Transformations.switchMap(responseResult) {
        it.data
    }

    val errorResult: LiveData<ResponseError> = Transformations.switchMap(responseResult) {
        it.error
    }
}
lang-kotlin
```

I triggered a LiveData ([SingleLiveEvent](https://gist.github.com/jutikorn/0bf472de02480f0cf3b64bb4d438767a)) at _onActivityCreated()_, and if you take a look at line 18, _Transformation.map()_ is called which mean _getTodoUsecase()_ will be called. After fetching is done, _responseResult_ will be assigned. And if you take a look again at line 22 and 26, _Transformation.switchMap() are_ called which means when the _responseResult’s value_ is updated, **_todoResult_** and **_errorResult_** instances will be pointed to the same instances as _responseResult’s properties.
_

**Tips:** OnChanged() method will not be called if MediatorLiveData is not observed at anywhere.

Reference:

[https://stackoverflow.com/questions/47575961/what-is-the-difference-between-map-and-switchmap-methods](https://stackoverflow.com/questions/47575961/what-is-the-difference-between-map-and-switchmap-methods)

---

Contact OOZOU: hello@oozou.com · +66 2544 0000 · https://oozou.com/contact

More for AI agents: https://oozou.com/llms.txt · every page has a markdown twin at its URL plus ".md"
