美文网首页Android 开发
关于Transformations.map和Transforma

关于Transformations.map和Transforma

作者: 乱逃 | 来源:发表于2019-09-30 12:38 被阅读0次

    用了 Android Architecture Component ** 也有一段时间了,期间也遇到过不少问题,也慢慢的解决了。mapswitchmap**是 LiveData Transformations提供的两个方法,那具体能干些啥呢?这是个好问题。如果知道RxJava,那么可以简单的对标 map和flatmap,咱先这么理解着,对不对先不管,起码,脑子中有个概念。

    Transformations.map

    先上源码

        /**
         * Applies the given function on the main thread to each value emitted by {@code source}
         * LiveData and returns LiveData, which emits resulting values.
         * <p>
         * The given function {@code func} will be executed on the main thread.
         * <p>
         * Suppose that you have a LiveData, named {@code userLiveData}, that contains user data and you
         * need to display the user name, created by concatenating the first and the last
         * name of the user. You can define a function that handles the name creation, that will be
         * applied to every value emitted by {@code useLiveData}.
         *
         * <pre>
         * LiveData<User> userLiveData = ...;
         * LiveData<String> userName = Transformations.map(userLiveData, user -> {
         *      return user.firstName + " " + user.lastName
         * });
         * </pre>
         *
         * @param source a {@code LiveData} to listen to
         * @param func   a function to apply
         * @param <X>    a type of {@code source} LiveData
         * @param <Y>    a type of resulting LiveData.
         * @return a LiveData which emits resulting values
         */
       @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形式的参数和一个方法,然后将这个LiveData。通过方法中的逻辑再输出为LiveData,最简单的用法就是像kotlin集合中的map用法。将集合中每个元素,做你方法中的操作,比如加减之类的。源码中的那个注释大概就是这个各操作,
    我们来扩展一下,假设现在有这么一个场景:界面上有个输入框,你输入一些字母 然后添加到数据库中。完了之后弹个吐司。
    我们来简写一下viewmodel中的代码:

    val  strLivedata=MutableLiveData<String>()
    fun yourFun(str:String)="新${str}被添加到数据库中"
    fun addStrClick(str:String)= { strLivedata.value=str}
    val addStr:LiveData=Transformations.map(strLivedata, ::yourFun)
    
    

    然后Activity中的代码:

    viewModel.addSt.observe(this, Observer{
    吐司(it)
    })
    
    button.setOnClickListener {
    viewModel.addStr(edittext.text.toString())
    }
    

    恩,基本上就是这样

    Transformations.switchMap

    switchmap 说实话,一开始的时候,我立即起来和用起来,比较费劲,尤其是配合了lamada表达式,更是难受。
    先上源码:

    
     /**
         * Creates a LiveData, let's name it {@code swLiveData}, which follows next flow:
         * it reacts on changes of {@code trigger} LiveData, applies the given function to new value of
         * {@code trigger} LiveData and sets resulting LiveData as a "backing" LiveData
         * to {@code swLiveData}.
         * "Backing" LiveData means, that all events emitted by it will retransmitted
         * by {@code swLiveData}.
         * <p>
         * If the given function returns null, then {@code swLiveData} is not "backed" by any other
         * LiveData.
         *
         * <p>
         * The given function {@code func} will be executed on the main thread.
         *
         * <p>
         * Consider the case where you have a LiveData containing a user id. Every time there's a new
         * user id emitted, you want to trigger a request to get the user object corresponding to that
         * id, from a repository that also returns a LiveData.
         * <p>
         * The {@code userIdLiveData} is the trigger and the LiveData returned by the {@code
         * repository.getUserById} is the "backing" LiveData.
         * <p>
         * In a scenario where the repository contains User(1, "Jane") and User(2, "John"), when the
         * userIdLiveData value is set to "1", the {@code switchMap} will call {@code getUser(1)},
         * that will return a LiveData containing the value User(1, "Jane"). So now, the userLiveData
         * will emit User(1, "Jane"). When the user in the repository gets updated to User(1, "Sarah"),
         * the {@code userLiveData} gets automatically notified and will emit User(1, "Sarah").
         * <p>
         * When the {@code setUserId} method is called with userId = "2", the value of the {@code
         * userIdLiveData} changes and automatically triggers a request for getting the user with id
         * "2" from the repository. So, the {@code userLiveData} emits User(2, "John"). The LiveData
         * returned by {@code repository.getUserById(1)} is removed as a source.
         *
         * <pre>
         * MutableLiveData<String> userIdLiveData = ...;
         * LiveData<User> userLiveData = Transformations.switchMap(userIdLiveData, id ->
         *     repository.getUserById(id));
         *
         * void setUserId(String userId) {
         *      this.userIdLiveData.setValue(userId);
         * }
         * </pre>
         *
         * @param trigger a {@code LiveData} to listen to
         * @param func    a function which creates "backing" LiveData
         * @param <X>     a type of {@code source} LiveData
         * @param <Y>     a type of resulting 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;
        }
    

    怎么理解呢,先看注释上的那个例子。
    定义一个用户id字符串的livedata,一个用户的livedata是通过Transformations.switchMap赋值的,就是传进去userid的livedata,然后通过这个id,去获取这个用户信息。再提供一个设置userid的方法,这样流程就串起来了。我们来扩展下:输入框中输入一个字符串,然后搜索,然后调用接口或者其他,用recycleview展示出来。
    先看viewModel中的代码:

    //查询的关键字livedata
    val query = MutableLiveData<String>()
    //你点击搜索是调用的方法
       fun queryByStr(str: String) = apply { query.value = str}
    //你的处理方法
    fun yourFun(str:String):LiveData<List<String>>{
    return 你网络或者数据库.query(str)
    }
    
    //查询结果livedata
    val queryResult=LiveData<List<String>>=Transformations.switchMap(
                query,
                ::yourFun
        )
    
    

    再看activity中的代码:

    recycleview初始化,设置adapter就不写了
    
    搜索.setOnClickListener{
    viewModel.queryByStr(搜索框.text.toString())}
    viewModel.queryResult.observe(this,Observer {
    //搜索结果变化了
    直接给adapter的数据源list改变,然后notify一下就完事了
    })
    
    

    大概基本上差不多就这样了,怎么说呢,光看代码的话,其实也不难理解,主要是本人对lamada表达是有点怵的慌,尤其是配合kotlin,本来一长串,结果给省略掉了,看起来贼费事,当然了。这个主要跟我的基础语法有关系,如果你深谙lamada表达式,那就没毛病了。总结一下。这两个操作符。map是你将你的函数用于你传参的livedata的数据通过函数体中的逻辑改变,然后将结果传到下游。而switchmap,转换跟map差不多,只不过传到下游的是livedata类型。rxjava中,map的作用是操作基本函数类型,而flatmap操作的是observable类型。当然了,还有一些能深入去理解的东西,我还没理解到。

    相关文章

      网友评论

        本文标题:关于Transformations.map和Transforma

        本文链接:https://www.haomeiwen.com/subject/mtpcpctx.html