首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >map()和switchMap()方法有什么区别?

map()和switchMap()方法有什么区别?
EN

Stack Overflow用户
提问于 2017-11-30 14:36:18
回答 12查看 39.4K关注 0票数 105

LiveData类的这两个方法之间有什么区别?官方的文档和教程对此相当模糊。在map()方法中,第一个参数称为,但在switchMap()中,称为触发器。这背后的理由是什么?

EN

回答 12

Stack Overflow用户

回答已采纳

发布于 2017-12-07 08:05:12

根据文件

Transformations.map()

对存储在LiveData对象中的值应用一个函数,并将结果传播到下游。

Transformations.switchMap()

类似于map,向存储在LiveData对象中的值应用一个函数,并向下游展开和分发结果。传递给switchMap()的函数必须返回LiveData对象

换句话说,我可能不是100%正确,但如果您熟悉RxJava;Transformations#map有点类似于Observable#map & Transformations#switchMap类似于Observable#switchMap

让我们举个例子,有一个LiveData,它发出一个字符串,我们希望用大写字母显示这个字符串。

一种方法如下:在一个活动或片段中

代码语言:javascript
运行
复制
Transformations.map(stringsLiveData, String::toUpperCase)
    .observe(this, textView::setText);

传递给map的函数只返回一个字符串,但最终返回一个LiveData的是Transformation#map

第二种方法;在一种活动或片段中

代码语言:javascript
运行
复制
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

票数 105
EN

Stack Overflow用户

发布于 2018-03-28 17:57:16

我的观察是,如果您的转换过程很快(不涉及数据库操作或网络活动),那么您可以选择使用map

但是,如果转换过程缓慢(涉及数据库操作或网络活动),则需要使用switchMap

在执行耗时的操作时使用switchMap

代码语言:javascript
运行
复制
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不适用于耗时的操作。

代码语言:javascript
运行
复制
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);
    }
}
票数 49
EN

Stack Overflow用户

发布于 2019-02-03 11:05:22

首先,map()switchMap()方法都是在主线程上调用的。它们与被用于快速或缓慢任务无关。但是,如果在这些方法中执行复杂的计算任务或耗时任务,而不是工作线程,解析或转换长和/或复杂的json响应(例如,因为它们是在UI线程上执行),则可能会导致UI滞后。

  • map()

map()方法的代码是

代码语言:javascript
运行
复制
@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;
}

它所做的是使用源LiveData,I是输入类型,并在LiveData上调用setValue(O),其中O是输出类型。

为了清楚起见,让我举一个例子。当用户更改时,您希望将用户名和姓氏写入textView。

代码语言:javascript
运行
复制
  /**
     * Changes on this user LiveData triggers function that sets mUserNameLiveData String value
     */
    private MutableLiveData<User> mUserLiveData = new MutableLiveData<>();

    /**
     * This LiveData contains the data(String for this example) to be observed.
     */
    public final LiveData<String> mUserNameLiveData;

现在,让我们在mUserLiveData更改时触发对mUserNameLiveData的字符串的更改。

代码语言:javascript
运行
复制
   /*
     * map() method emits a value in type of destination data(String in this example) when the source LiveData is changed. In this example
     * when a new User value is set to LiveData it trigger this function that returns a String type
     *         
     *              Input, Output
     * new Function<User, String>
     *
     *  public String apply(User input) { return output;}
     */

    // Result<Output>                        Source<Input>               Input, Output
    mUserNameLiveData = Transformations.map(mUserLiveData, new Function<User, String>() {
        @Override
        public String apply(User input) {
            // Output
            return input.getFirstName() + ", " + input.getLastName();
        }
    });

让我们用MediatorLiveData做同样的事情

代码语言:javascript
运行
复制
 /**
     * MediatorLiveData is what {@link Transformations#map(LiveData, Function)} does behind the scenes
     */
    public MediatorLiveData<String> mediatorLiveData = new MediatorLiveData<>();
    /*
     * map() function is actually does this
     */
    mediatorLiveData.addSource(mUserLiveData, new Observer<User>() {
        @Override
        public void onChanged(@Nullable User user) {
            mediatorLiveData.setValue(user.getFirstName() + ", " + user.getLastName());
        }
    });

如果在活动或片段上观察到MediatorLiveData,就会得到与观察LiveData<String> mUserNameLiveData相同的结果。

代码语言:javascript
运行
复制
userViewModel.mediatorLiveData.observe(this, new Observer<String>() {
    @Override
    public void onChanged(@Nullable String s) {
        TextView textView = findViewById(R.id.textView2);

        textView.setText("User: " + s);

        Toast.makeText(MainActivity.this, "User: " + s, Toast.LENGTH_SHORT).show();
    }
});
  • switchMap()

每次更改switchMap()时,都会返回相同的MediatorLiveData,而不是新的 LiveData。

它的源代码是

代码语言:javascript
运行
复制
@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;
}

基本上,它所做的是创建一个最终的MediatorLiveData,并像map to ()一样设置结果,但是这次函数返回LiveData

代码语言:javascript
运行
复制
   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;
    }

因此,map()接受LiveData<User>并将其转换为String,例如,如果User对象更改了名称字段。

switchMap()接受一个字符串并使用它获取LiveData<User>。使用字符串从web或db查询用户,结果得到一个LiveData<User>

票数 34
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47575961

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档