map() 和 switchMap() 方法有啥区别?

Posted

技术标签:

【中文标题】map() 和 switchMap() 方法有啥区别?【英文标题】:What is the difference between map() and switchMap() methods?map() 和 switchMap() 方法有什么区别? 【发布时间】:2018-05-14 12:43:29 【问题描述】:

LiveData 类的这两种方法有什么区别?官方文档和教程对此非常模糊。在 ma​​p() 方法中,第一个参数称为 source,但在 switchMap() 中,它称为 trigger。这背后的原因是什么?

【问题讨论】:

【参考方案1】:

根据文档

Transformations.map()

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

Transformations.switchMap()

类似于映射,将函数应用于存储在 LiveData 对象中的值,然后解包并将结果分发到下游。 传递给 switchMap() 的函数必须返回一个 LiveData 对象

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

举个例子,有一个 LiveData 发出一个字符串,我们想用大写字母显示该字符串。

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

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

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

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

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

【讨论】:

这将解释命名。因此,它们都应该在每次底层 LiveData 更改时触发,并且“切换”意味着 LiveData 将被切换到另一个 LiveData 对象。谢谢! 很好的解释 - 我在我的仓库中添加了 switchMap 和 Map 组合的示例。github.com/febaisi/ListenableWorkerExample/blob/master/app/src/… .. 'SwitchMap' 仅用于监听按钮事件并切换到正确的 LiveData,它是 Worker 结果的映射。我希望它也有帮助。 Both Transformations(map, switchMap) 返回 LiveData 对象。【参考方案2】:

我的观察是,如果你的转换过程很快(不涉及数据库操作或网络活动),那么你可以选择使用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);
    

【讨论】:

简单而清晰的响应,大多数响应只是一次又一次地解释它在内部是如何工作的,但我关心的第一件事是为什么我会使用它,而不需要了解它的内部行为。谢谢。【参考方案3】:

Map() 在概念上与 RXJava 中的用法相同,基本上是在更改另一个 LiveData 的参数

SwitchMap() 相反,您将用另一个替换 LiveData 本身!典型的情况是,例如,当您从存储库中检索一些数据并“消除”以前的 LiveData(垃圾收集,通常使内存更有效)时,您传递了一个 new LiveData 来执行相同的操作(例如获取查询)

【讨论】:

到目前为止,唯一一个用原始直接示例反映现实的答案【参考方案4】:

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

ma​​p()

map() 方法的代码是

@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。

  /**
     * 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 的字符串更改。

   /*
     * 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做同样的事情

 /**
     * 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());
        
    );

如果您在 Activity 或 Fragment 上观察 MediatorLiveData,您将获得与观察 LiveData&lt;String&gt; mUserNameLiveData 相同的结果

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() 每次 SourceLiveData 更改时都会返回相同的 MediatorLiveData 而不是 LiveData。

它的源代码是

@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 does() 一样设置为 Result 但这个 time 函数返回 LiveData

   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&lt;User&gt; 并将其转换为String,例如如果User 对象更改名称字段更改。

switchMap() 接受一个字符串并使用它获取LiveData&lt;User&gt;。使用字符串从 web 或 db 查询用户并得到 LiveData&lt;User&gt; 作为结果。

【讨论】:

很好的答案!【参考方案5】:

上面已经有一些不错的答案了,但我还是很纠结,直到我理解为止,所以我将尝试用我的思维方式为人们解释一个具体的例子,而不涉及技术细节和代码。

mapswitchMap 中都有一个来源(或触发器)实时数据,在这两种情况下您都需要将其转换为另一个实时数据。您将使用哪一个 - 取决于您的转换正在执行的任务。

map

考虑在任何地方都使用的同一个简单示例 - 您的 实时数据包含一个 User 对象 - LiveData&lt;User&gt;,它指向当前登录的用户。你想在你的 UI 中显示一个文本 Current user: &lt;USERNAME&gt;。在这种情况下,来自源的每个更改信号都应恰好触发生成的“映射”LiveData 的一个信号。例如,当前 User 对象是“Bob”,那么 UI 文本显示 Current user: Bob。一旦您的 LiveData&lt;User&gt; 触发更改,您的 UI 将观察它并将文本更新为 Current user: Alice。非常简单,线性,一对一的变化。

switchMap

考虑以下示例 - 您想要创建一个 UI 来显示名称与给定搜索词匹配的用户。我们可以非常聪明地将搜索词作为 LiveData!所以它将是一个LiveData&lt;String&gt;,每次用户输入一个新的查询字符串时,我们的Fragment/Activity 将简单地将文本输入值设置为ViewModel 中的这个实时数据。结果,此实时数据将触发更改信号。一旦我们得到这个信号,我们就开始搜索用户。现在让我们考虑一下我们的搜索是如此之快以至于它立即返回一个值。此时您认为您可以只使用 map 并返回匹配的用户,这将更新 UI。好吧,您现在将遇到一个错误 - 假设您定期更新数据库,并且在下次更新后出现更多与搜索词匹配的用户!如您所见,在这种情况下,源触发器(搜索词)不一定会导致映射实时数据的单个触发器,给 UI 的映射实时数据可能仍需要在添加新用户后继续触发值数据库。此时你可能会说,我们可以返回一个“更智能”的实时数据,它不仅会等待源触发器,还会监控数据库中匹配给定术语的用户(你可以使用 @987654338 做到这一点@DB 开箱即用)。但随之而来的另一个问题是——如果搜索词发生变化怎么办?所以你的术语是x,它触发了一个查询用户并密切关注数据库的实时数据,它返回userx, userxx,然后五分钟后它返回userx, userxxx等等。然后将术语更改为y。现在我们需要以某种方式停止收听为我们用户提供x 的智能实时数据,并使用新的智能实时数据切换它,它将监控并为我们提供y 的用户他们的名字。这正是 switchMap 正在做的事情!请注意,此切换需要以这样一种方式完成,即在您的 UI 中您只需编写一次switchMap(...).observe,这意味着switchMap 必须返回一个包装器LiveData,它将在整个执行过程中保持不变,但会为我们切换后台的实时数据源。

结论

虽然第一眼看起来一样,但是mapswitchMap的用例是不一样的,你会感觉到是哪一个一旦你开始实现你的案例就可以使用,主要是当你意识到在你的映射函数中你必须从你的其他模块(如Repositories)中调用一些代码,这些代码返回LiveData

【讨论】:

很好的解释。我对差异有一个清晰的了解,但是如果我们在搜索用户时使用“地图”而不是“开关地图”来获取用户对象并将其包装在相同的实时数据中,那会是什么问题。为什么我们在查询新用户时需要更改 livedata 实例本身? @frangulyan @HariKiran 因为单个用户搜索的结果是动态的,它会随着时间而变化,这就是它是实时数据的原因。因此,假设您致电val searcResultLiveData = database.getFirstUserMatching("alice") 并开始收听“alice”的搜索结果更改。然后你需要将它映射到字符串“Found: ”。您的映射将不起作用,因为您将在 searcResultLiveData 上调用 map,但是一旦您更改搜索词,您的搜索结果实时数据必须更改,您还需要更新映射的实时数据。 @HariKiran 在现实世界中,你会从另一个角度遇到这种情况。您将为某个对象 X 创建一个实时数据 - 我们称之为 val liveX: LiveData&lt;X&gt;。然后你需要保留一个实时数据对象Y,它依赖于X:val liveY: LiveData&lt;Y&gt;。实现地图是合乎逻辑的:val liveY = liveX.map ...。然后你将开始在... 和 bam 中编写映射函数!您意识到在您的映射函数中,您必须调用返回实时数据的第三方函数(如 DB 调用)!那你别无选择,只能使用switchMap 而不是map【参考方案6】:

切换地图: 假设我们正在寻找用户名 Alice。存储库正在创建该 User LiveData 类的新实例,然后我们显示用户。一段时间后,我们需要查找用户名 Bob,存储库会创建一个新的 LiveData 实例,并且我们的 UI 订阅了该 LiveData。所以此时,我们的 UI 订阅了两个 LiveData 实例,因为我们从未删除前一个。因此,这意味着每当我们的存储库更改用户的数据时,它都会发送两次订阅。现在,我们如何解决这个问题……?

我们真正需要的是一种机制,允许我们在想要观察新来源时停止从先前来源观察。为此,我们将使用 switchMap。在底层,switchMap 使用 MediatorLiveData,只要添加了新源,它就会删除初始源。简而言之,它为我们完成了删除和添加新 Observer 的所有机制。

但地图是静态的,当您不必每次都强制获取新的实时数据时使用它

【讨论】:

【参考方案7】: 使用map,您最终拥有相同的源实时数据,但它的数据(值)在发出之前随提供的函数而变化 使用switchMap,您只需作为触发器使用源实时数据来返回独立的实时数据(当然您可以在函数输入中使用触发器数据) 触发器:导致 livedata 的观察者 onChanged() 调用的一切

【讨论】:

【参考方案8】:

简而言之,命名类似于rx map/switchMap。

地图是一对一的映射,很容易理解。

另一方面,SwitchMap 一次只映射最近的值以减少不必要的计算。

希望这个简短的答案可以轻松解决大家的问题。

【讨论】:

【参考方案9】:

Transformation.map()

fun <X, Y> map(trigger: LiveData<X>, mapFunction: Function<X, Y> ): LiveData<Y>?

trigger - LiveData 变量一旦改变就会触发mapFunction 执行。

mapFunction - 当trigger LiveData 发生更改时调用的函数。参数 X 是对trigger 的引用(通过it)。函数返回指定类型 Y 的结果,最终由map() 作为 LiveData 对象返回。

当您想要在trigger LiveData 变量更改时执行操作(通过mapFunction)时,请使用map()map() 将返回一个 LiveData 对象,在调用 mapFunction 时应观察该对象。

示例:

假设有一个简单的投球手姓名列表、他们的平均数和他们的差点平均数:

data class Bowler(val name:String, val average:Int, var avgWHDCP:Int)
var bowlers = listOf<Bowler>(Bowler("Steve", 150,150), Bowler ("Tom", 210, 210))

假设一个 MutableLiveData Int 变量包含一个让分增量值。当此值更改时,需要重新计算列表中所有投球手的avgWHDCP。最初它被设置为零。

var newHDCP:MutableLiveData<Int> = MutableLiveData(0)

创建一个调用Tranformation.map() 的变量。它的第一个参数是newHDCP。它的第二个参数是当newHDCP 改变时要调用的函数。在此示例中,该函数将遍历所有投球手对象,为投球手列表中的每个投球手计算新的avgWHDCP,并将结果作为 LiveData Bowler 对象的可观察列表返回。请注意,在此示例中,原始的非 LiveData 投球手列表和返回的投球手列表将反映相同的值,因为它们引用了相同的数据存储。但是,函数的结果是可观察的。投球手的原始列表不是因为它没有设置为 LiveData。

var updatedBowlers: LiveData<List<Bowler>> = Transformations.map(newHDCP) 
    bowlers.forEach  bowler ->
        bowler.avgWHDCP  = bowler.average +  it
    
    return@map bowlers

在您的代码中的某处,添加一个更新newHDCP 的方法。在我的示例中,当单击单选按钮时,newHDCP 将被更改,并且该进程将触发调用Transformations.map() 中指定的函数

rbUpdateBy20.setOnCheckedChangeListener  _, isChecked ->
        viewModel.bowlingBallObject.newHDCP.value = 20

最后,所有这些只有在观察到updatedBowlers 时才会起作用。这将以OnViewCreated()等方法放置在您的Activity或Fragment中

viewModel.updatedBowlers.observe(viewLifecycleOwner, Observer  bowler ->
    if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED) 
        refreshRecycler()
    
)

如果您想要更简洁一些,并且您真的不需要对 updatedBowlers 的实时引用,那么您可以将 updateBowlers 与观察者结合使用:

Transformations.map(viewModel.newHDCP) 
    viewModel.bowlers.forEach  bowler ->
        bowler.avgWHDCP  = bowler.average +  it
    
    return@map viewModel.bowlers
.observe(viewLifecycleOwner, Observer  bowler ->
    if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED) 
        refreshRecycler()
    
)

基本上就是这样。每当您更改newHDCP 的值时,Transformation.map() 中指定的函数将被调用,它将用新计算的avgWHDCP 转换保龄球对象并返回List&lt;Bowler&gt; 的 LiveData 对象

Transformation.switchMap()

fun <X, Y> switchMap(source: LiveData<X>, switchMapFunction: Function<X, LiveData<Y>!>): LiveData<Y>

source - LiveData 变量一旦改变就会触发switchMapFunction 执行。

switchMapFunction - 当源 LiveData 发生更改时调用的函数。参数 X 引用同一个源对象(通过it)。 switchMapFunction 函数必须返回一个 LiveData 结果,该结果实际上是通过Transformation.switchMap() 返回的。从本质上讲,这允许您将 LiveData 容器对象的一个​​引用替换为另一个。

当您有一个引用 LiveData 对象的变量并且您想将该变量切换到另一个变量时使用switchMap(),或者以不同的方式说您想刷新现有的 LiveData 容器。这很有用,例如,如果您的 LiveData 变量正在引用数据库数据存储并且您想使用不同的参数重新查询。 switchMap 允许您重新执行查询并替换为新的 LiveData 结果。

示例

假设一个数据库存储库包含来自 BowlingBall DAO 表的一堆保龄球查询:

private val repository  = BowlingBallRepository(application)

我想执行一个查询来获取活动或非活动保龄球,具体取决于用户指定的内容。通过 UI,用户可以选择活动或非活动,因此我的查询需要同时处理两者。所以我创建了一个MutableLiveData 变量来保持活动或非活动状态。在这个例子中,我默认为“A”表示活跃。

var activeFlag:MutableLiveData<String> = MutableLiveData(“A”)

现在,我们需要一个 LiveData 变量来保存我的查询结果,以获取特定状态的所有保龄球。所以我创建了一个名为allBowlingBalls 类型为LiveData&lt;List&lt;BowlingBallTable&gt;&gt;? 的变量并将其分配给Transformation.switchMap。我将activeFlag 变量以及将接收相同activeFlag 变量(通过it)的lambda 函数传递给switchMap 函数,并且该函数调用数据库存储库中的查询以重新获取所有已通过状态的保龄球。 lambda 函数的 LiveData 结果通过switchMap 方法传回,并重新分配给allBowlingBalls

private var allBowlingBalls: LiveData<List<BowlingBallTable>>? = Transformations.switchMap(activeFlag) repository.getAllBalls(it)

我需要一种方法来触发allBowlibgBalls 的刷新。同样,这将在activeFlag 更改时完成。在您的代码中的某处,添加一个函数来更新activeFlag。在我的示例中,当单击单选按钮时,activeFlag 将被更改,并且该进程将触发调用Transformations.switchMap() 中指定的函数

rbActive.setOnCheckedChangeListener  _, isChecked ->
    if (isChecked) 
        viewModel.activeFlag.value = ActiveInactive.ACTIVE.flag
        refreshRecycler()
    

最后,所有这些只有在观察到 allBowlingBalls 时才会起作用。所以首先创建一个函数来获取 allBowlingBalls:

fun getAllBowlingBalls():LiveData<List<BowlingBallTable>>? 
    return  allBowlingBalls

然后在getAllBowlingBalls()上放置一个观察者:

viewModel.getAllBowlingBalls()?.observe(viewLifecycleOwner, Observer  balls ->
    if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED) 
        refreshRecycler()
    
)

就是这样。每次activeFlag 更改时,allBowlingBalls 将通过调用存储库来刷新,allBowlingBalls 上的观察者的onChange 事件将触发。一种用于构建动态搜索引擎的简单技术。

【讨论】:

【参考方案10】:

让我用一个例子来解释一下我的理解。考虑一个学生数据类

data class Student(val name: String, val marks: Int)

Transformation.map()

将 LiveData 的值转换为另一个值。它获取值,将函数应用于该值,并将函数的输出设置为它返回的 LiveData 上的值。这是如何将其用于上述数据类的示例:

 val student: LiveData<Student> = (get liveData<Student> from DB or network call)
 val studentName: LiveData<String> = Transformations.map(student) it.name

在这里,我们从网络或数据库中获取学生 LiveData,然后从作为 Student 对象的 LiveData 中获取值,然后获取学生的姓名并将其映射到另一个 LiveData。

Transformation.switchMap()

将 LiveData 的值转换为另一个 LiveData。考虑我们要为学生实现搜索功能。每次搜索文本更改时,我们都希望更新搜索结果。下面的代码展示了它是如何工作的。

val searchQuery: LiveData<String> = ...

val searchResults: LiveData<List<Student>> = 
    Transformations.switchMap(searchQuery)  getSearchResults(it) 

fun getSearchResults(query: String): LiveData<List<Student>> = (get liveData<List<Student>> from DB or network call)

所以这里每次在 searchQuery 中有一个新值时,都会调用 getSearchResults 并带有一个新的搜索查询,并且 searchResults 会被更新。

【讨论】:

你能解释一下为什么在搜索学生的用例中不能使用Transformation.map()。会有什么问题?【参考方案11】:

这里是一个简短的

如果您希望结果值反复更改,请使用 swithMap() 如果只是一次操作,请改用 ma​​p()

示例:如果您想显示现场比赛的分数,请使用 swithMap() 。 如果你想显示一个球队的球员名单,请使用 map()

【讨论】:

【参考方案12】:

根据我的经验,两者都是用您更新的内容(livedata #1)和您真正关心/观察的内容(livedata #2)建立一个桥梁作为回报。这座桥是必要的,这样您就可以将观察者(即您的片段)的生命周期带到查看模型,然后他们可以自动删除对所有LiveData 的订阅。这是LiveData 从一开始的主要承诺之一。所以,这将信守承诺。

switchMap 的情况下,桥是动态 意味着总是有一个 LiveData 从函数(lambda)返回 - 所以你切换到这个新的LiveDatamap 是静态的。

希望对你有帮助。

【讨论】:

【参考方案13】:

它们有不同的用例:

如果您有源 LiveData,并且只想将该 LiveData 中的值更改为其他数据类型,请使用 map

如果您有一个源 LiveData 和一个返回 LiveData 的函数,并且您想要创建一个 LiveData 以根据该函数返回的 LiveData 更新值。使用switchMap

分析源代码,我们看到switchmapmap 都返回了一个新的MediatorLiveData 实例。

map 接收一个为 MediatorLiveData 返回新值的函数,而switchmap 接收一个返回 LiveData 新实例的函数(然后如果 LiveData 的新实例的值发生变化,则使用它来更新 MediatorLiveData 的值)

换句话说,如果输入函数的 LiveData 值发生变化,switchmap 的 LiveData 值也会发生变化,switchmap 还具有取消注册从该输入函数返回的先前 LiveData 的额外好处。

【讨论】:

以上是关于map() 和 switchMap() 方法有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

如何以及在何处使用 Transformations.switchMap?

了解rxjs中的SwitchMap

steam账号分国家地区吗 怎么看自己的账号是啥区

Java 8 中的 map() 和 flatMap() 方法有啥区别?

C++ unordered_map 的 rehash() 和 reserve() 方法有啥区别?

React:使用 array.find 和 array.map 方法设置状态有啥区别? [复制]