В чем разница между методами map() и switchMap ()?

в чем разница между этими 2 методами класса LiveData? Официальный документ и учебник довольно расплывчаты по этому поводу. В map () Метод первый параметр называется источник а в switchMap() это называется триггер. В чем причина этого?

3 ответов


согласно документации

преобразований.map ()

применяет функцию к значению, хранящемуся в объекте LiveData, и распространяет результат вниз по потоку.

преобразований.switchMap()

подобно map, применяет функцию к значению, хранящемуся в объекте LiveData, и разворачивает и отправляет результат вниз по потоку. функция передана switchMap() должен возвращать объект LiveData.

другими словами, Я не могу быть на 100% прав, но если вы знакомы с RxJava;Transformations#map вроде как Observable#map & Transformations#switchMap похож на Observable#flatMap.

давайте возьмем пример, есть LiveData, который испускает строку, и мы хотим отобразить эту строку заглавными буквами.

один подход будет следующим: в деятельности или фрагменте

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

функции перешел в map возвращает только строку, но это Transformation#map что в конечном итоге возвращает LiveData.

второй подход; в деятельности или фрагмент

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;
}

если вы видите Transformations#switchMap фактически подменил LiveData. Итак, опять же согласно документации функция, переданная switchMap (), должна возвращать объект LiveData.

Итак, в случае map это источник LiveData вы трансформируетесь и в случае switchMap шли LiveData будет действовать как триггер на котором он переключится на другой LiveData после разворачивания и отправки результата вниз по течению.


мое наблюдение заключается в том, что если ваш процесс преобразования быстрый (не включает работу с базой данных или сетевую активность), то вы можете использовать map.

однако, если ваш процесс преобразования медленный (включая работу с базой данных или сетевую активность), вам нужно использовать switchMap

switchMap используется при выполнении трудоемкой операцией

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 не подходит для трудоемкой операцией

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);
    }
}

Map () концептуально идентичен использованию в RXJava, в основном вы меняете параметр LiveData в другом enter image description here

SwitchMap() вместо этого вы собираетесь заменить LiveData сам с другим! Типичный случай, когда вы получаете некоторые данные из репозитория, например, и "устранить" предыдущую LiveData (для сбора мусора, чтобы сделать его более эффективным память обычно), вы передаете new LiveData, которые выполняют одно и то же действие( например, получение запроса)