RXJava 常用操作符整理(持续更新)

参考文章:

扔物线大哥神作(对于转换的原理及RXJava基础讲的非常透彻):



http://gank.io/post/560e15be2dca930e00da1083

操作符系列好文(系统学习操作符的不二选择):

http://blog.chinaunix.net/uid-20771867-id-5187376.html

         RXJava最爽的莫过于链式编程,代码条理清晰,可以把各种回调嵌套、时序混乱、类型转换等的问题以一条链式调用统统搞定。而这么神奇的功能就需要操作符来支持。

         看一段简单的代码:

  Observable.just("张三","李四","王五").subscribe(new Action1<String>()
        {
            @Override public void call(String s)
            {
                Log.d("name",s);
            }
        });

         就是输出几个简单的字符串,其中just就是一个操作符(同理create、from)也是。在我理解中,操作符就是在数据流中,对数据进行各种转换、处理的一些封装好的方法。

而我们常用的操作符,除了刚才说的create、from、just这些,最常用的就是用于数据转换处理(也可以用于其他用途)的map和flatMap了。除此之外,还有可以帮我们解决搜集多个API结果状态的merge啊(吐血推荐)、防抖throttleFirst啊(再也不用不停地getCurrentTime了)等等。。。

Map

      如果有一个模块,可以获取到每个用户的所有信息,然后在UI上我需要绘制用户的头像,这样需要在用户信息里获取到头像的Url。这个用户信息包括了:

    class UserInfoBean
    {
        public String avatar;
        public String name;
        public String phoneNum;
    }

       那如果按照正常的办法,我们会这样去完成:

   ImageView ivAvatar = (ImageView)findViewById(R.id.iv_user_avatar);
        Observable.just(userInfo).subscribe(new Action1<UserInfoBean>()
        {
            @Override public void call(UserInfoBean bean)
            {
                Glide.with(mContext).load(bean.avatarUrl).into(ivAvatar);
            }
        });


      讲道理说subscriber中应该只响应结果,这里的subsriber只期望获取一个url用来展示头像,而对其他的东西并不感兴趣,那么好吧,修改一下代码:

      ImageView ivAvatar = (ImageView)findViewById(R.id.iv_user_avatar);
        Observable.just(userInfo.avatarUrl).subscribe(new Action1<String>()
        {
            @Override public void call(String url)
            {
                Glide.with(mContext).load(url).into(ivAvatar);
            }
        });

         在这里,我们使observable中调用next的时候直接传入一个头像的Url,这样不就好了嘛~  可是,如果我要在其他地方需要获取到用户的名字怎么办?现在这个Observable中直接返回的是头像Url啊 ,难道我要重写一个吗?

         这时候就可以用到map了。

        

     ImageView ivAvatar = (ImageView)findViewById(R.id.iv_user_avatar);
        TextView tvName = (TextView)findViewById(R.id.tv_user_name);
        //更新头像
        getUserInfo().map(new Func1<UserInfoBean,String>()
        {
            @Override public String call(UserInfoBean bean)
            {
                return bean.avatarUrl;
            }
        }).subscribe(new Action1<String>()
        {
            @Override public void call(String url)
            {
                Glide.with(mContext).load(url).info(ivAvatar);
            }
        });

        //更新用户昵称
        getUserInfo().map(new Func1<UserInfoBean,String>()
        {
            @Override public String call(UserInfoBean bean)
            {
                return bean.name;
            }
        }).subscribe(new Action1<String>()
        {
            @Override public void call(String name)
            {
                tvName.setText(name);
            }
        });
      Observable getUserInfo()
      {
        return Observable.just(userInfo);
       }


          map可以把obserable传出的数据做一个转换再放到subscriber的onNext方法中执行~~~这样既实现了observable的复用,又使得subcriber中的工作减轻,最重要的是提高了代码的逼格。

flatMap

       也行你会觉得map没啥用,甚至有些画蛇添足,那么看下接下来的这个进阶加强版。

       还是刚才的那个例子,现在每个用户有若干好友,那么需要在userInfo中加入一个List,这里存放着所有好友的用户Id

   class UserInfoBean
    {
        public String avatarUrl;
        public String name;
        public String phoneNum;
        public List<String> friendList;
    }

        现在我想获取这个用户所有好友的姓名,那好,那我正常情况下肯定是需要遍历这个好友列表,获取每个好友的id然后去查询好友姓名吧。像这样
      

        UserInfoBean userInfoBean = getCurrentUser();

        Observable.just(userInfoBean).subscribe(new Action1<UserInfoBean>()
        {
            @Override public void call(UserInfoBean bean)
            {
                for(String id:bean.friendList)
                {
                    UserInfoBean friend = queryUserById(id);
                    System.out.print(friend.name);
                }
            }
        });


          为什么我都用RXJava这么洋气的东西了,还要在响应方法中写这么多的代码呢,而且还用到了for each!好吧,解决这个问题就用到flatMap了!

          先看使用flatMap改写的代码!

          

        Observable.just(userInfoBean).flatMap(new Func1<UserInfoBean, Observable<String>>() {
            @Override
            public Observable<String> call(UserInfoBean userInfoBean)
            {
                List<String> names = new ArrayList<String>();
                for(String id:userInfoBean.friendList)
                {
                    UserInfoBean friend = queryUserById(id);
                    names.add(friend.name);
                }
                return Observable.from(names);
            }
        }).subscribe(new Action1<String>() {
            @Override
            public void call(String name) {
                System.out.print(name);
            }
        });

          在flatMap的参入中放入一个Func1对象!这个Fucn1对象封装了个有一个入参并有返回值call方法。之前还有个Action封装的是不同入参但没有返回值的call方法,现在对比下,顾名思义,func作为一个方法,需要有返回值,所以funcX都是封装了不同数量入参且有一个返回值的方法。而Action作为一个动作,不需要有反馈,所以ActionX封装的是不同数量入参且没有返回值的方法。

          接着看flatMap中func1的call方法做了些什么。在call方法中遍历了所有好友的id,然后根据Id查询出好友的姓名,然后通过from将姓名返回,这样就可以通过from来实现了1对多的一个转换,而且把所有耗时的逻辑操作都封装到异步方法中执行,使得subsciber只去响应。

          从这可以看出,flatMap中存放的是一个转换的操作,但是这个转换的操作是在什么时候执行调用的呢?而且func1中的call返回的为什么是一个observbale对象?这块儿我觉得理解起来还是有一定难度的,至少对于我来讲,耗费了不少的时间来理解。

         这地方建议参考扔物线的文章(最上面的链接)并结合源码来看,我在这边简单的把我个人的理解记录下。

         首先,点开flatMap的源码:

    public final <R> Observable<R> flatMap(Func1<? super T, ? extends Observable<? extends R>> func) {
        if (getClass() == ScalarSynchronousObservable.class) {
            return ((ScalarSynchronousObservable<T>)this).scalarFlatMap(func);
        }
        return merge(map(func));
    }

        忽略同步的那个判断,直接看return,发现这里有两个方法,分别是merge和map,点开map:

       

    public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
        return lift(new OperatorMap<T, R>(func));
    }

        这里注意两点:1.利用func创建了一个OperatorMap(一个实现了Operator接口的类)。2.将这个OperatorMap放入List中。看到Operator了吧,这下和我们这篇文章的题目贴切了吧~~~ 而且List这个东西这的是整个转换操作符的精华,这里的代码很少,但是很重要:

       

  public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
        return new Observable<R>(new OnSubscribe<R>() {
            @Override
            public void call(Subscriber<? super R> o) {
                try {
                    Subscriber<? super T> st = hook.onLift(operator).call(o);
                    try {
                        // new Subscriber created and being subscribed with so 'onStart' it
                        st.onStart();
                        onSubscribe.call(st);
                    } catch (Throwable e) {
                        // localized capture of errors rather than it skipping all operators 
                        // and ending up in the try/catch of the subscribe method which then
                        // prevents onErrorResumeNext and other similar approaches to error handling
                        Exceptions.throwIfFatal(e);
                        st.onError(e);
                    }
                } catch (Throwable e) {
                    Exceptions.throwIfFatal(e);
                    // if the lift function failed all we can do is pass the error to the final Subscriber
                    // as we don't have the operator available to us
                    o.onError(e);
                }
            }
        });
    }

        可以看到list传入了一个operator对象,返回了一个Observable对象。我们上面使用flatMap的例子中,我们自己定义了一个输出某个用户信息的Observable为ObservableA,打印这个用户所有好友姓名的subscriber为subscriberB。那么设这个List中生成的Observable对象为ObserableB,看下这个ObservableB中的call方法,这个call方法中利用传入的operator和原始的subsriberA生成了一个新的subscriber对象为subsriberB,然后调用OnSubsribe.call来注册这个新的subsriberB。Ok,那么看一下这个subseriberB都做了什么,这就要先看下OperatorMap这个类中做了什么。

     

public final class OperatorMap<T, R> implements Operator<R, T> {

    final Func1<? super T, ? extends R> transformer;

    public OperatorMap(Func1<? super T, ? extends R> transformer) {
        this.transformer = transformer;
    }

    @Override
    public Subscriber<? super T> call(final Subscriber<? super R> o) {
        return new Subscriber<T>(o) {

            @Override
            public void onCompleted() {
                o.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                o.onError(e);
            }

            @Override
            public void onNext(T t) {
                try {
                    o.onNext(transformer.call(t));
                } catch (Throwable e) {
                    Exceptions.throwOrReport(e, this, t);
                }
            }

        };
    }

}

       这个构造方法中的入参就是我们在flatMap中定义的func1,而call方法的入参就是我们的subsriberA,会发现在这里call方法中,新建了一个subsriber,这个subsriber就是subsriberB,而这个subsriberB其实就是对subsriberA进行了一个带来,其中OnComplete和OnError都是直接调用A的,只有在onNext中做了个转换,而这个转换的方法就是func1中的call方法。也就是说,现在其实是subscriberB订阅了observbaleA,而subcriberB在获取了ObservableA的处理结果后,经过转换,又发送给了ObserableA。而此时,subsriberA订阅的就不是ObserableA,而是ObserableB了,也就是说B在A之间做了一个代理的作用。

       

猜你喜欢

转载自blog.csdn.net/u010696826/article/details/52690227