android EventBus的简单使用

前言

  RxAndroid是RxJava在Android上的一个扩展,大牛JakeWharton的项目。听说和Retorfit、OkHttp组合起来使用,效果不是通常的好。并且用它彷佛能够彻底替代eventBus和OTTO,这么牛的东西固然要研究研究了 ,看看它到底有多厉害。
正文
相关资源

  RxJava的GitHub地址:https://github.com/ReactiveX/RxJava 
  RxAndroid的GitHub地址:https://github.com/ReactiveX/RxAndroid 
  中文文档:https://mcxiaoke.gitbooks.io/rxdocs/content/ 
  一篇写的比较好的入门RxJava的文章的地址:http://gank.io/post/560e15be2dca930e00da1083
1.RxJava是干吗的

  Rx(Reactive Extensions)是一个库,用来处理事件和异步任务,在不少语言上都有实现,RxJava是Rx在Java上的实现。简单来讲,RxJava就是处理异步的一个库,最基本是基于观察者模式来实现的。经过Obserable和Observer的机制,实现所谓响应式的编程体验。 
  Android的童鞋都知道,处理异步事件,现有的AsyncTask、Handler,不错的第三方事件总线EventBus、OTTO等等均可以处理。而且大部分童鞋应该都很熟练了。并且经我目前的学习来看,RxJava这个库,上手确实有门槛,不是拿来就能用。可是做为一个猿,那些可能出现的优秀的框架技术,及时的跟进和学习是必要的,从中汲取养分才能帮助本身成长。何况有童鞋已经表示,它彻底能够替代EventBus和OTTO,来看看吧。
2.RxJava的优点

  最归纳的两个字:简洁。并且当业务越繁琐越复杂时这一点就越显出优点——它可以保持简洁。 
  简单的demo看不出来,真正投入项目使用了应该就有体会了。它提供的各类功能强悍的操做符真的很强大。
3.基本使用流程

  这里只介绍Android Studio的接入方式,若是你还在用Eclipse的话,我建议你换了。 
  配置buile.gradle:(如下为当前最新版本,若有更新请到上述GitHub连接查看更新)

    dependencies {
      compile 'io.reactivex:rxandroid:1.2.1'
      compile 'io.reactivex:rxjava:1.1.6'
      }


  配置完以后就可使用RxJava的API了。介绍两个个关键的类: 
  (1)Observable (2)Subscriber 即:被观察者(Observable)和观察者(Subscriber),其实我以为叫发布者和订阅者更好理解一些,但你们都叫被观察者和观察者。 
  主干的使用过程就是1.建立被观察者。2.建立观察者。3.将两者创建联系。完毕。而后被观察中发出信息触发观察者的动做,执行相应的方法,就这样。你先别急着吐槽它很平庸。它的强大在于这个过程当中提供的各类操做变换的技巧会让你能够简洁的处理至关繁琐的代码逻辑。 
先看一个简单的demo:

            //建立一个被观察者(发布者)
            Observable observable = Observable.create(new Observable.OnSubscribe<Integer>() {
                @Override
                public void call(Subscriber<? super Integer> subscriber) {
                    subscriber.onNext(1001);
                    subscriber.onNext(1002);
                    subscriber.onNext(1003);
                    subscriber.onCompleted();
                }
            });
     
            //建立一个观察者
            Subscriber<Integer> subscriber = new Subscriber<Integer>() {
                @Override
                public void onCompleted() {
                    Log.d(TAG, "onCompleted.. ");
                }
     
                @Override
                public void onError(Throwable e) {
                    Log.d(TAG, "subscriber onError.. " + e.getMessage());
                }
     
                @Override
                public void onNext(Integer integer) {
                    Log.d(TAG, "onNext.. integer:" + integer);
                }
            };
     
            //注册观察者(这个方法名看起来有点怪,还不如写成regisiterSubscriber(..)或者干脆addSubscriber(..))
            //注册后就会开始调用call()中的观察者执行的方法 onNext() onCompleted()等
            observable.subscribe(subscriber);

  

  上面的例子中,当Observable发射数据时,会依次调用Subscriber的onNext()方法,将发射的数据做为参数传给onNext(),若是出错,则会调用Subscriber的onError()方法,完成全部数据发射后,调用onCompleted()方法,整个过程完毕。 
  可是,subcribe()方法默认在当前线程被调用。因此,这样使用的话,被观察者和观察者的全部的动做都是在同一个线程完成的,没卵用… 
  可是固然确定不会就这个程度了,RxJava有两个方法能够很方便的指定观察者和被观察者代码运行的线程,RxAndroid还有一个扩展,能够指定在UI线程运行。你懂的! 
以下:

    //设置观察者和发布者代码所要运行的线程后注册观察者
    observable.subscribeOn(Schedulers.immediate())//在当前线程执行subscribe()方法
    .observeOn(AndroidSchedulers.mainThread())//在UI线程执行观察者的方法
    .subscribe(subscriber);

  

  经过Scheduler做为参数来指定代码运行的线程,很是方便,好用到不行…其余经常使用的参数还有: 
  Schedulers.immediate(): 直接在当前线程运行,至关于不指定线程。这是默认的 Scheduler。  
  Schedulers.newThread(): 老是启用新线程,并在新线程执行操做。 
  Schedulers.io(): I/O 操做(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差很少,区别在于 io() 的内部实现是是用一个无数量上限的线程池,能够重用空闲的线程,所以多数状况下 io() 比 newThread() 更有效率。不要把计算工做放在 io() 中,能够避免建没必要要的线程。 
  Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操做限制性能的操做,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操做放在 computation() 中,不然 I/O 操做的等待时间会浪费 CPU。 
  另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操做将在 Android 主线程运行。
4.Observable建立方式

  以上介绍了主干使用流程,从这里咱们往细一点再看。前文说了,RxJava的强大之处在于它的各类操做符。在建立Observable对象的方式上,一样有不少方便的操做符的实现,上面是经过Observable.create()方法建立的observable对象,这里介绍其余几个经常使用的方法。 
   
  经过from建立Observable:

         //Teacher为一个数据Bean,包含姓名,年龄,住址三个字段
         List<Teacher> teachers = new ArrayList<>();
            for (int i = 0; i < 4; i++) {
                teachers.add(new Teacher("name" + i, i, "place" + i));
            }
            //from方法支持继承了Interable接口的参数,因此经常使用的数据结构(Map、List..)均可以转换
            Observable fromObservale = Observable.from(teachers);
            fromObservale.subscribe(new Subscriber<Teacher>() {
                @Override
                public void onCompleted() {
                    Log.i(TAG, "from(teachers)  onCompleted");
                }
     
                @Override
                public void onError(Throwable e) {
                    Log.e(TAG, "from(teachers)  " + e.getMessage());
                }
     
                @Override
                public void onNext(Teacher teacher) {
                    //依次接收到teachers中的对象
                    Log.d(TAG, "from(teachers)  onNext:" + teacher.toString());
                }
            });

  

  用from方法建立Observable,能够传入一个数组,或者一个继承了Iterable的类的对象做为参数,也就是说,java中经常使用的数据结构如List、Map等均可以直接做为参数传入from()方法用以构建Observable。这样,当Observable发射数据时,它将会依次把序列中的元素依次发射出来。 
   
  经过just建立Observable:  

    //Just相似于From,可是From会将数组或Iterable的元素具取出而后逐个发射,而Just只是简单的原样发射,将数组或Iterable当作单个数据。
    //Just接受一至九个参数,返回一个按参数列表顺序发射这些数据的Observable
    Observable justObservable = Observable.just(1, "someThing", false, 3.256f, new Teacher("Jhon", 25, "NewYork"));
    justObservable.subscribe(new Subscriber() {
        @Override
        public void onCompleted() {
            Log.i(TAG, "just(...)  onCompleted");
        }
     
        @Override
        public void onError(Throwable e) {
            Log.d(TAG, "just(...)  onError:" + e.getMessage());
        }
     
        @Override
        public void onNext(Object o) {
            Log.d(TAG, "just(...)  onNext:" + o.toString());
        }
    });

  
  just直接接收object做为参数,原样发射出来,也是很是方便的。 
   
经过timer建立Observable:  

    //timer()建立一个Observable,它在一个给定的延迟后发射一个特殊的值 设定执行方法在UI线程执行
    //延时两秒后发射值
    //实测 延时2s后发送了一个0
    Observable timerObservable = Observable.timer(2, TimeUnit.SECONDS, AndroidSchedulers.mainThread());
       timerObservable.subscribe(
               new Subscriber() {
                   @Override
                   public void onCompleted() {
                       Log.i(TAG, "timer(...)  onCompleted");
                       refreshStr("timer(...)  onCompleted\n");
                   }
     
                   @Override
                   public void onError(Throwable e) {
                       Log.e(TAG, "timer(...)  onError:" + e.getMessage());
                       refreshStr("timer(...)  onError:" + e.getMessage());
                   }
     
                   @Override
                   public void onNext(Object o) {
                       Log.d(TAG, "timer(...)  onNext:" + o.toString());
                       refreshStr("timerObservable 延时两秒触发 发送值:" + o.toString());
                   }
               }
       );

  

  timer有定时的做用,延时发送一个值0。 
   
经过range建立Observable(这里叠加使用一个repeat方法):  

    //range 发射从n到m的整数序列 能够指定Scheduler设置执行方法运行的线程
    //repeat方法能够指定重复触发的次数
    Observable rangeObservable = Observable.range(3, 7).repeat(2);
    rangeObservable.subscribe(
    //在不写观察者的状况下,可使用Action1和Action0这两个接口来实现不完整定义的回调; 参见:ActionSubscriber
    //Action1<T>能够代替实现onNext(); Action1<Throwable>能够代替实现onError(); Action0能够代替实现onConplete()
            new Action1() {
                @Override
                public void call(Object o) {
                    Log.e(TAG, "range(3, 7).repeat(2)  onNext:"+o.toString());
                }
            },
            new Action1<Throwable>() {
                @Override
                public void call(Throwable throwable) {
                    Log.e(TAG, "range(3, 7).repeat(2)  "+throwable.getMessage());
                }
            },
            new Action0() {
                @Override
                public void call() {
                    Log.i(TAG, "range(3, 7).repeat(2)  onCompleted");
                }
            });

  

  range发射从n到m的整数序列,repeat能够指定重复次数,以上发射的次序为:3,4,5,6,7,3,4,5,6,7。这里用到的Action0和Action1是两个能够替代Subscriber的接口,具体能够参见相关文档和源码实现,这里不深刻介绍。 
  其余还有Interval、Defer、Start等方法就不一一介绍了,本文主要是帮助初次接触的童鞋入门,RxJava的操做符很是丰富,这里很难一一说明,更多的内容要还须要你们本身去熟悉和探究。
.变换操做

  除了多样的Observable建立方式,RxJava还有一个神奇的操做就是变换。经过本身定义的方法,你能够将输入的值变换成另外一种类型再输出(好比输入url,输出bitmap),单一变换、批量变换、甚至实现双重变换,嵌套两重异步操做!而且代码格式一如既往的干净平整。是否是很牛? 
   
  使用map()方法作转换:

    Runnable run = new Runnable() {
         @Override
         public void run() {
             //将文件路径转换为bitmap发出 观察者直接收到bitmap进行处理
             Observable observable = Observable.just(imgFilePath);
             observable.map(new Func1<String, Bitmap>() {
                 @Override
                 public Bitmap call(String imgFilePath) {
                     return getBitmapFromAssets(imgFilePath);
                 }
             }).subscribeOn(Schedulers.immediate())//当前线程(子线程)发布
                     .observeOn(AndroidSchedulers.mainThread())//UI线程执行(更新图片)
                     .subscribe(new Subscriber<Bitmap>() {
                         @Override
                         public void onCompleted() {
                             Log.i(TAG, "observable.map(..)  onCompleted");
                         }
     
                         @Override
                         public void onError(Throwable e) {
                             Log.i(TAG, "observable.map(..)  onError" + e.getMessage());
                         }
     
                         @Override
                         public void onNext(Bitmap bitmap) {
                             //显示图片
                             iv.setImageBitmap(bitmap);
                         }
                     });
         }
     };
     new Thread(run).start();



  map()方法是最基本的变换操做,这里只变换了一个数据,将文件路径解析为Bitmap显示出来。你固然也能够多传入几个参数或者用from操做符传入一个数组或者集合等,批量操做,而且同时指定代码运行的线程。并且这些全部的操做均可以在一条链式代码中所有完成,易读易维护。你是否是已经有一点体会到它的威力了? 
   
  flatMap()实现双重变换 
  flatMap()将一个发射数据的Observable变换为多个Observables,而后将它们发射的数据合并后放进一个单独的Observable。即:第一次转换时,它依次将输入的数据转换成一个Observable,而后将这些Observable发射的数据集中到一个Observable里依次发射出来。以为莫名其妙?来看一个实际例子:

    Subscriber subscriber = new Subscriber<Integer>() {
        @Override
        public void onCompleted() {
            Log.i(TAG,"Observable.just(array1,array2).flatMap  onCompleted\n\n");
        }
     
        @Override
        public void onError(Throwable e) {
            Log.e(TAG,"Observable.just(array1,array2).flatMap   onError  "+e.getMessage());
        }
     
        @Override
        public void onNext(Integer integer) {
            Log.d(TAG,"Observable.just(array1,array2).flatMap  integer = "+integer);
        }
    };
     
    //flatMap能够实现一个双重转换,在它的回调方法中会返回一个observable对象,但它并不会直接发射这个对象
    //而是将这个observable对象要发射的值 集中到一个新的observable对象中依次发射
    //如本例,第一层Observable依次发射两个数组,通过flatmap转换以后,变成变成两个依次发射数组元素的observable
    // 最后在subscriber中接收到的直接是整型数,等于将两个数组"铺开"了,直接发射整数,这就是大概地"flat"的含义吧
    // flatMap方法能够很灵活的使用,实现双重变换,知足不少不一样状况下的需求,好比处理嵌套的异步代码等,很是棒!
    Integer[] array1 = {1, 2, 3, 4}, array2 = {5, 6, 7, 8};
    Observable.just(array1,array2).flatMap(new Func1<Integer[], Observable<?>>() {
        @Override
        public Observable<?> call(Integer[] ints) {
            Observable observable = Observable.from(ints);
            return observable;
        }
    }).subscribe(subscriber);

    

  这里flatMap()方法将最初传入的两个数组在第一次变换时,经过from操做符变换成两个Observable,而后在将这两个Observable发射的数据所有集中到一个新的Observable中集中发射,等于将两个数组”铺开”了,依次发射出来它们的元素。具体转换的方法由你指定,使用的方式是比较灵活的。 
  好比有的商城类应用的需求:先要拿到某类别的一个产品列表,而后列表中有具体产品展现图片的url,须要你拿到产品列表信息后依次去请求图片,成功后更新到UI页面上,使用flatMap,你确定知道怎么写了吧,是否是比CallBack跳来跳去的舒服一些?

  scan()变换 
  scan操做符对原始Observable发射的第一项数据应用一个函数,而后将那个函数的结果做为本身的第一项数据发射。它将函数的结果同第二项数据一块儿填充给这个函数来产生它本身的第二项数据。它持续进行这个过程来产生剩余的数据序列。 
  当看到这里的时候,我已经由衷的在感叹,这些操做符实在太TM丰富了,而后对它的强大已经开始有所体会和感悟了。这种产生斐波那契数列的操做都给封装进去了,并且函数由你自定义,你能用它作成什么,可能在灵感到来以前你本身都想不到。 
  demo代码:

    //scan 会将输入的第一个元素看成参数作一个函数运算(函数由你实现,规定须要两个参数,此时另外一个默认没有),而后发射结果
    // 同时,运算结果会被看成函数的与第二个参数与第二个元素再进行函数运算,完成后发射结果
    // 而后将这个结果与第三个元素做为函数的参数再次运算...直到最后一个元素
    Observable.just(1, 2, 3, 4).scan(new Func2<Integer, Integer, Integer>() {
        @Override
        public Integer call(Integer integer, Integer integer2) {
            //integer是第一个元素或上一次计算的结果,integer2是下一轮运算中新的序列中元素
            Log.d(TAG, "scan call   integer:" + integer + "   integer2:" + integer2);
            return integer + integer2;
        }
    }).subscribe(new Subscriber<Integer>() {
        @Override
        public void onCompleted() {
            Log.i(TAG, "Observable.just(1,2,3,4).scan   onCompleted..");
            initViewState();
        }
     
        @Override
        public void onError(Throwable e) {
            Log.e(TAG, "Observable.just(1,2,3,4).scan  onError  " + e.getMessage());
        }
     
        @Override
        public void onNext(Integer integer) {
            Log.d(TAG, "Observable.just(1,2,3,4).scan  onNext()..  integer = " + integer);
            /**
             * 第一次为1,而后是3(1+2),6(3+3),10(6+4)
             */
        }
    });

    

  注释和上面的说明都很清晰了,就再也不赘述。一样,关于转换操做,也还有不少其余的操做符,如wiindow() buffer() 等已实现的方法,具体参见文档吧。
6.过滤、结合操做

  在文档的分类中,还有两片基础API是过滤和结合的操做符,例如:Filter、Skip、Take、Merage、Zip等等,原本打算一块儿列举的,可是想一想其实若是熟悉了上面的内容,这两块相关的API上手其实也很容易了。若是入门目的已经达到,再讲这个显得有点啰嗦。因此略去,若是之后有心得,在开篇另讲那些操做符的使用,RxJava的知识,主要仍是要靠本身多熟悉,多研究。
尾声

  本文主要但愿帮助初次接触RxJava的童鞋入门,讲的一些基础知识,RxJava太大,内容太丰富,入门以后须要下的功夫也很多,但愿你们都能day day up! 
  最后,如发现内容有误,请斧正! 
  很是感谢!
相关文章
相关标签/搜索