Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between map() and switchMap() methods?

What is the difference between those 2 methods of the LiveData class? The official doc and tutorial are pretty vague on that. In the map() method the first parameter called source but in the switchMap() it called trigger. What's the rationale behind that?

like image 253
Igor Bubelov Avatar asked Nov 30 '17 14:11

Igor Bubelov


People also ask

What is the difference between MAP and SwitchMap?

Map is 1 to 1 mapping which is easy to understand. SwitchMap on the other hand only mapping the most recent value at a time to reduce unnecessary compute.

What is difference between MAP and SwitchMap RXJS?

map(function(value) { return value*10; }). subscribe(observer); SwitchMap - switchMap will subscribe to all the inner Observables inside the outer Observable but it does not merge the inner Observables. It instead switches to the latest Observable and passes that along to the chain.

What is SwitchMap in android?

switchMap(LiveData<X> trigger, Function<X, LiveData<Y>> func) Creates a LiveData, let's name it swLiveData , which follows next flow: it reacts on changes of trigger LiveData, applies the given function to new value of trigger LiveData and sets resulting LiveData as a "backing" LiveData to swLiveData .

What is mediator live data?

The LiveData component is part of Android Jetpack and is nowadays widely used for implementing the Observer pattern while automatically considering the Lifecycle of the respective Android app. It is mostly used for updating the UI with a new state of the respective ViewModel.


2 Answers

As per the documentation

Transformations.map()

Applies a function on the value stored in the LiveData object, and propagates the result downstream.

Transformations.switchMap()

Similar to map, applies a function to the value stored in the LiveData object and unwraps and dispatches the result downstream. The function passed to switchMap() must return a LiveData object.

In other words, I may not be 100% correct but if you are familiar with RxJava; Transformations#map is kind of similar to Observable#map & Transformations#switchMap is similar to Observable#switchMap.

Let's take an example, there is a LiveData which emits a string and we want to display that string in capital letters.

One approach would be as follows; in an activity or fragment

Transformations.map(stringsLiveData, String::toUpperCase)     .observe(this, textView::setText); 

the function passed to the map returns a string only, but it's the Transformation#map which ultimately returns a LiveData.

The second approach; in an activity or fragment

Transformations.switchMap(stringsLiveData, this::getUpperCaseStringLiveData)             .observe(this, textView::setText);  private LiveData<String> getUpperCaseStringLiveData(String str) {     MutableLiveData<String> liveData = new MutableLiveData<>();     liveData.setValue(str.toUpperCase());     return liveData; } 

If you see Transformations#switchMap has actually switched the LiveData. So, again as per the documentation The function passed to switchMap() must return a LiveData object.

So, in case of map it is the source LiveData you are transforming and in case of switchMap the passed LiveData will act as a trigger on which it will switch to another LiveData after unwrapping and dispatching the result downstream.

like image 71
Rupesh Avatar answered Oct 17 '22 10:10

Rupesh


My observation is that, if your transformation process is fast (Doesn't involve database operation, or networking activity), then you can choose to use map.

However, if your transformation process is slow (Involving database operation, or networking activity), you need to use switchMap

switchMap is used when performing time-consuming operation

class MyViewModel extends ViewModel {     final MutableLiveData<String> mString = new MutableLiveData<>();     final LiveData<Integer> mCode;       public MyViewModel(String string) {          mCode = Transformations.switchMap(mString, input -> {             final MutableLiveData<Integer> result = new MutableLiveData<>();              new Thread(new Runnable() {                 @Override                 public void run() {                     // Pretend we are busy                     try {                         Thread.sleep(5000);                     } catch (InterruptedException e) {                         e.printStackTrace();                     }                      int code = 0;                     for (int i=0; i<input.length(); i++) {                         code = code + (int)input.charAt(i);                     }                      result.postValue(code);                 }             }).start();              return result;         });          if (string != null) {             mString.setValue(string);         }     }      public LiveData<Integer> getCode() {         return mCode;     }      public void search(String string) {         mString.setValue(string);     } } 

map is not suitable for time-consuming operation

class MyViewModel extends ViewModel {     final MutableLiveData<String> mString = new MutableLiveData<>();     final LiveData<Integer> mCode;       public MyViewModel(String string) {          mCode = Transformations.map(mString, input -> {             /*                  Note: You can't launch a Thread, or sleep right here.                  If you do so, the APP will crash with ANR.             */             /*             try {                 Thread.sleep(5000);             } catch (InterruptedException e) {                 e.printStackTrace();             }             */              int code = 0;             for (int i=0; i<input.length(); i++) {                 code = code + (int)input.charAt(i);             }             return code;         });          if (string != null) {             mString.setValue(string);         }     }      public LiveData<Integer> getCode() {         return mCode;     }      public void search(String string) {         mString.setValue(string);     } } 
like image 23
Cheok Yan Cheng Avatar answered Oct 17 '22 09:10

Cheok Yan Cheng