Android-RxJava 常见API使用以及线程转换要点

Android-RxJava 常见API使用以及线程转换要点_第1张图片

什么是RxJava?
RxJava 在 GitHub上的自我介绍是 “a library for composing asynchronous and event-based programs using observable sequences for the Java VM”(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava。
接下来不多说什么了,直接进入今天的主题吧

一.API使用

RxJava的API使用,包括Observable的创建,以及变换,以及数据的过滤等

1.1 Observable创建

Observable的创建有几种方式,比如create,just,from,interval,timer

1.1.1 create

是Rxjava中创建Observable最基本的方法*,例子如下-创建Observable时,传入onSubsribe作为参数,会被存储在Observable对象中,当Observable被订阅时,就会触发其call方法。

private void testRxMethod_create() { 
      Observable observable = Observable.create(new Observable.OnSubscribe() { 
            @Override
            public void call(Subscriber subscriber) {
                 RxBeanInfo info = new RxBeanInfo(); info.setName("lqm.test");
                 subscriber.onNext(info); subscriber.onCompleted(); }}); 
                 Subscriber subscriber = new Subscriber() { 
                      @Override 
                      public void onCompleted() {
                           Log.i("rxjava", "onCompleted"); 
                      } 

                      @Override
                      public void onError(Throwable e) {
                           Log.i("rxjava", "error"); 
                      } 
 
                      @Override
                      public void onNext(RxBeanInfo o) { 
                           Log.i("rxjava", o.getName()); 
                      }}; 
                     //通过调用subscribe方法使观察者和订阅者产生关联,一旦订阅,Observable就会调用call(). observable.subscribe(subscriber); }
11-17 14:27:14.513 14944-14944/pa.test.com.testapp I/rxjava: lqm.test
11-17 14:27:14.513 14944-14944/pa.test.com.testapp I/rxjava: onCompleted

1.1.2 just

通过调用just方法,传入你想发送的数据源,当订阅者进行订阅的时候就开始打印数据,需要注意的是,just()方法最多可传10个参数,它们会按照传入的参数的顺序来发射它们。

private void testRxMethod_just() { 
       Observable observable = Observable.just("1", "2", "3","4", "5","6","7","8","9","10");
       Subscriber subscriber = new Subscriber() { 
            @Override 
            public void onCompleted() { 
                Log.i("rxjava", "onCompleted"); 
            } 
            @Override
            public void onError(Throwable e) { 
                Log.i("rxjava", "error"); 
            } 
            @Override 
            public void onNext(String o) { 
                Log.i("rxjava", o); 
            }}; 
       observable.subscribe(subscriber); 
}

1.1.3 from

该方法参数是一个数组,然后from会将其拆分为一个个对象,发射出去。

private void testRxMethod_from() {
     List items = new ArrayList<>(); 
     items.add("1"); 
     items.add("2");
     items.add("3");
     Observable observable = Observable.from(items);
     Subscriber subscriber = new Subscriber() { 
           @Override 
           public void onCompleted() {
               Log.i("rxjava", "onCompleted"); 
           }
           @Override 
           public void onError(Throwable e) { 
                Log.i("rxjava", "error");
           } 
           @Override 
           public void onNext(String o) { 
                Log.i("rxjava", o); 
           }
      };
     observable.subscribe(subscriber); 
}
11-17 14:44:13.043 30921-30921/pa.test.com.testapp I/rxjava: 1
11-17 14:44:13.043 30921-30921/pa.test.com.testapp I/rxjava: 2
11-17 14:44:13.043 30921-30921/pa.test.com.testapp I/rxjava: 3
11-17 14:44:13.043 30921-30921/pa.test.com.testapp I/rxjava: onCompleted

1.1.4 interval

定时器,该方法会每隔一段时间发射消息,interval()函数的两个参数:一个指定两次发射的时间间隔,另一个是用到的时间单位。

private void testRxMethod_interval() { 
      Observable.interval(2, TimeUnit.SECONDS)
                .subscribe(new Observer() {
                          @Override 
                          public void onCompleted() { 
                               Log.i("rxjava", "onCompleted"); 
                          } 
                          @Override 
                          public void onError(Throwable e) { 
                                Log.i("rxjava", "onError"); 
                           } 
                          @Override 
                          public void onNext(Long number) { 
                                Log.i("rxjava", "onNext"+number); 
                           }
             }); 
}

1.1.5 timer

可达到延时器效果之用,订阅后,Observable发射出一个0,就结束了,调用 onCompleted()。

private void testRxMethod_timer() {
     Observable.timer(3,TimeUnit.SECONDS)
          .subscribe(new Observer() { 
                  @Override 
                  public void onCompleted() {
                       Log.i("rxjava", "onCompleted"); 
                  } 
                  @Override 
                  public void onError(Throwable e) { 
                        Log.i("rxjava", "onError");
                  } 
                  @Override 
                  public void onNext(Long number) { 
                        Log.i("rxjava", "onNext"+number); 
                  } 
           }); 
}

1.2 Observable变换以及过滤

1.2.1 map

是对对象的一种直接变换函数,它会接受一个Fun函数当作入参,然后将它应用到每一个由Observable发射的值上,它将输入的数据处理后,返回一种新形式的数据,可以是任一类型。应用场景可以是:将图片路径(String)处理后返回Bitmap图片,或者计算原始数据,处理后成为需要的数据。

private void testRxMethod_map() { 
      Observable.just(6) 
                .map(new Func1() { 
                     @Override 
                     public String call(Integer integer) { 
                         return integer/3+""; 
                     } 
                 }) 
               .subscribe(new Action1() { 
                   @Override 
                   public void call(String s) { 
                       Log.d("lqm","call:"+s);
                   }
       });
 }


1.2.2 flatMap

Observable.flatMap()接收一个Observable的输出作为输入,同时输出另外一个Observable。

private void testRxMethod_flatMap() { 
     Observable.just("girl;boy;man") 
               .flatMap(new Func1>() { 
                    @Override 
                    public Observable call(String s) { 
                        return Observable.from(s.split(";")); 
                    } 
                 }) 
               .subscribe(new Action1() { 
                             @Override 
                              public void call(String s) { 
                                 Log.d("lqm", "onNext:" + s); 
                              } 
                          },  new Action1() { 
                             @Override 
                             public void call(Throwable throwable) { 
                                 Log.d("lqm", "onerror"); 
                             } 
                         }, new Action0() { 
                            @Override public void call() { 
                                Log.d("lqm", "onComplete"); 
                         } 
          }); 
}
11-17 15:41:04.743 18653-18653/pa.test.com.testapp D/lqm: onNext:girl
11-17 15:41:04.743 18653-18653/pa.test.com.testapp D/lqm: onNext:boy
11-17 15:41:04.743 18653-18653/pa.test.com.testapp D/lqm: onNext:man
11-17 15:41:04.743 18653-18653/pa.test.com.testapp D/lqm: onComplete

要对比下flatMap跟map,flatMap传入的参数是Observable,返回的也是 Observable,虽然两者都是传入一个对象,再转化成一个新对象,但是这一点还是很有区别的,关于flatMap的原理,这边引用下扔物线的一段话来解释:

flatMap() 的原理是这样的:1. 使用传入的事件对象创建一个 Observable 对象;
2. 并不发送这个 Observable, 而是将它激活,于是它开始发送事件;
3. 每一个创建出来的 Observable 发送的事件,都被汇入同一个 Observable ,而这个 Observable
   负责将这些事件统一交给 Subscriber 的回调方法。

1.2.3 filter

过滤方法,使用这个方法来过滤掉一些我们不需要的数据,返回false,说明该对象不符合要求,会被过滤; 返回true,说明该对象可以正常往下走,符合标准。

private void testRxMethod_filter() { 
     String[] strArr = {"a123","b123","c123","d123"}; 
     Observable.from(strArr) 
               .filter(new Func1() { 
                      @Override 
                      public Boolean call(String s) { 
                           return s.contains("a") || s.contains("b") || s.contains("c"); 
                      } 
               })
              .subscribe(new Action1() { 
                    @Override 
                    public void call(String s) { 
                        Log.d("lqm","call:"+s); 
                    } 
               }); 
}
11-17 20:39:54.761 32378-32378/pa.test.com.testapp D/lqm: call:a123
11-17 20:39:54.761 32378-32378/pa.test.com.testapp D/lqm: call:b123
11-17 20:39:54.761 32378-32378/pa.test.com.testapp D/lqm: call:c123

1.2.4 distinct

在一个序列中去掉重复数据

private void testRxMethod_distinct() { 
      Observable.just("Jack", "Honey","Lucy","Lucy","Jane")
                .distinct()
                .subscribe(new Subscriber() {
                     @Override 
                     public void onCompleted() { 
                         Log.i("lqm","onCompleted"); 
                     } 
                     @Override
                     public void onError(Throwable e) { 
                     } 
 
                     @Override 
                     public void onNext(String s) { 
                               Log.i("lqm","onNext" + s); 
                     } 
            }); 
}
11-17 20:47:00.141 19536-19536/pa.test.com.testapp I/lqm: onNextJack
11-17 20:47:00.141 19536-19536/pa.test.com.testapp I/lqm: onNextHoney
11-17 20:47:00.141 19536-19536/pa.test.com.testapp I/lqm: onNextLucy
11-17 20:47:00.141 19536-19536/pa.test.com.testapp I/lqm: onNextJane
11-17 20:47:00.141 19536-19536/pa.test.com.testapp I/lqm: onCompleted

这边需要注意的是,distinct只能区别基本类型的重复以及是否同一对象,若是不同对象内容相同,是不能去重的

private void testRxMethod_distinct() { 
      RxBeanInfo info1 = new RxBeanInfo(); 
      info1.setName("jack"); 
      RxBeanInfo info2 = new RxBeanInfo(); 
      info2.setName("jack"); 
      RxBeanInfo info3 = new RxBeanInfo(); 
      info3.setName("jack"); 
      Observable.just(info1,info2,info3) 
                .distinct()
                .subscribe(new Subscriber() { 
                       @Override
                       public void onCompleted() { 
                            Log.i("lqm","onCompleted"); 
                       } 
                       @Override
                       public void onError(Throwable e) { 
                       } 
                       @Override 
                       public void onNext(RxBeanInfo s) { 
                             Log.i("lqm","onNext" + s.getName());
                       } 
            }); 
}
11-17 20:50:01.101 25465-25465/pa.test.com.testapp I/lqm: onNextjack
11-17 20:50:01.101 25465-25465/pa.test.com.testapp I/lqm: onNextjack
11-17 20:50:01.101 25465-25465/pa.test.com.testapp I/lqm: onNextjack
11-17 20:50:01.101 25465-25465/pa.test.com.testapp I/lqm: onCompleted

这些API是比较常用了,目前就讲到这些,如果有兴趣的,可以去给Android开发者的RxJava 详解去细看。

二.线程转换要点

这边主要介绍的是RxJava 的 Schedulers(调度器) 功能
对于任何 Observable 你可以定义在两个不同的线程。

  1. 使用 Observable.observeOn() 可以定义在一个线程上,可以用来监听和检查从 Observable 最新发出的 items (Subscriber 的 onNext,onCompleted 和 onError 方法会执行在 observeOn 所指定的线程上)。
  2. 使用 Observable.subscribeOn() 来定义一个线程,subscribeOn() 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。

RxJava 默认情况下是单线程的,你会需要利用 observeOn() 和 subscribeOn() 方法为你的应用带来多线程操作。RxJava 附带了几个现成的 Schedulers 给 Observables 使用,如:Schedulers.io() (用于 I/O 操作),Schedulers.computation()(计算工作),和 Schedulers.newThread()(为任务创建的新线程),另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。

了解到这些,我们来看看实际Rxjava是在线程间是如何运行的,这边会分case 来详解 1.只配置了 observeOn,但是在不同的位置,会有什么样的影响呢?

private void observableEvent() {
     Log.d("lqm","mainthread :"+android.os.Process.myTid()); 
     Observable.just(1) 
               .map(new Func1() { 
                    @Override 
                    public String call(Integer integer) {
                        Log.d("lqm","map:"+android.os.Process.myTid()); 
                        return integer+"a"; 
                    } 
                }) 
                .filter(new Func1() { 
                        @Override 
                        public Boolean call(String s) {
                             Log.d("lqm","filter:"+android.os.Process.myTid()); 
                             return s.contains("1"); 
                        } 
                }) 
                .observeOn(Schedulers.io()) 
                .subscribe(new Action1() {
                       @Override 
                       public void call(String s) {
                          Log.d("lqm","call:"+android.os.Process.myTid()); 
                       } 
          }); 
}
11-17 21:08:58.551 7624-7624/pa.test.com.testapp D/lqm: mainthread :7624
11-17 21:08:58.591 7624-7624/pa.test.com.testapp D/lqm: map:7624
11-17 21:08:58.591 7624-7624/pa.test.com.testapp D/lqm: filter:7624
11-17 21:08:58.591 7624-8857/pa.test.com.testapp D/lqm: call:8857

从上面运行结果可以看出,主线程id为7624,map()和filter()运行在主线程,由于调用subscribe()时调用了observeOn(Schedulers.io()),所以call()方法运行在io线程上。

那如果我们将observeOn()提前呢,会不会对线程造成影响呢?

private void observableEvent() { 
     Log.d("lqm","mainthread :"+android.os.Process.myTid()); 
     Observable.just(1)
               .observeOn(Schedulers.io()) 
               .map(new Func1() { 
                   @Override
                   public String call(Integer integer) {
                        Log.d("lqm","map:"+android.os.Process.myTid()); 
                        return integer+"a"; 
                    } 
                }) 
                .filter(new Func1() { 
                       @Override 
                       public Boolean call(String s) {
                           Log.d("lqm","filter:"+android.os.Process.myTid()); 
                           return s.contains("1"); 
                       } 
               }) 
              .subscribe(new Action1() { 
                         @Override
                         public void call(String s) {
                              Log.d("lqm","onNext:"+android.os.Process.myTid()); 
                         } 
               }); 
 }
11-18 10:02:35.691 21563-21563/pa.test.com.testapp D/lqm: mainthread :21563
11-18 10:02:35.711 21563-22093/pa.test.com.testapp D/lqm: map:22093
11-18 10:02:35.711 21563-22093/pa.test.com.testapp D/lqm: filter:22093
11-18 10:02:35.711 21563-22093/pa.test.com.testapp D/lqm: onNext:22093

看到了没有,现在map(),filter()和onNext()都运行在IO线程上了 所以目前来看,observeOn()对除了Subscriber操作产生影响,还对map,filter等产生影响,但是只会对ObserveOn()操作后的动作产生影响

接下来继续测试。

private void observableEvent() { 
      Log.d("lqm","mainthread :"+android.os.Process.myTid()); 
      Observable.just(1) 
                .map(new Func1() { 
                     @Override 
                     public String call(Integer integer) {
                         Log.d("lqm","map:"+android.os.Process.myTid()); 
                         return integer+"a"; 
                      } 
                 })
                .filter(new Func1() { 
                     @Override 
                     public Boolean call(String s) {         
                         Log.d("lqm","filter :"+android.os.Process.myTid()); 
                         return s.contains("1"); 
                     } 
                 }) 
                 .subscribeOn(Schedulers.io()) 
                 .subscribe(new Action1() { 
                       @Override 
                       public void call(String s) {
                          Log.d("lqm","onNext:"+android.os.Process.myTid()); 
                 } 
           });
 }
11-19 23:09:14.845 21061-21061/pa.test.com.testapp D/lqm: mainthread :21061
11-19 23:09:14.905 21061-22008/pa.test.com.testapp D/lqm: map:22008
11-19 23:09:14.905 21061-22008/pa.test.com.testapp D/lqm: filter :22008
11-19 23:09:14.905 21061-22008/pa.test.com.testapp D/lqm: onNext:22008

由结果可以看出,map()等三个方法其实最终是运行在IO线程上,虽然subscribeOn()是在map后面才调用的,但是依然影响了线程运行,为什么呢?

因为 observeOn() 指定的是 Subscriber 的线程,而这个 Subscriber 并不是(严格说应该为『不一定是』,
但这里不妨理解为『不是』)subscribe() 参数中的 Subscriber ,而是 observeOn() 执行时
的当前 Observable 所对应的 Subscriber ,即它的直接下级 Subscriber 。换句话说,
observeOn() 指定的是它之后的操作所在的线程。因此如果有多次切换线程的需求,只要在每个想要切换线程的位置
调用一次 observeOn() 即可。
subscribeOn() 的线程切换发生在 OnSubscribe 中,即在它通知上一级 OnSubscribe 时,
这时事件还没有开始发送,因此 subscribeOn() 的线程控制可以从事件发出的开端就造成影响;
而 observeOn() 的线程切换则发生在它内建的 Subscriber 中,即发生在它即将给下一级 
Subscriber 发送事件时,因此 observeOn() 控制的是它后面的线程。 

引用来自《给 Android 开发者的 RxJava 详解》

请看下下面这个实例,可以更好地理解这段话

//observableEvent(new String[]{"any"});
private void observableEvent(String[] folders) { 
       Log.d("lqm","mainthread :"+android.os.Process.myTid());
       Observable.from(folders) 
                 .flatMap(new Func1>() { 
                        @Override 
                        public Observable call(String file) {
                                Log.d("lqm","flatMap:"+android.os.Process.myTid()); 
                                return Observable.from(file.split(";")); 
                         } 
                 }) 
                .filter(new Func1() { 
                    @Override 
                    public Boolean call(String s) {
                           Log.d("lqm","filter:"+android.os.Process.myTid()); 
                           return s.contains("a") || s.contains("b") || s.contains("c"); 
                     } 
                }) 
                .observeOn(Schedulers.io()) 
                .map(new Func1() { 
                    @Override 
                    public String call(String s) {
                       Log.d("lqm","1map:"+android.os.Process.myTid()); 
                       return s.concat(" map1 "); 
                     } 
                }) 
               .map(new Func1() { 
                   @Override 
                   public String call(String s) {                        
                       Log.d("lqm","2map:"+android.os.Process.myTid()); 
                       return s.concat(" mqp2 "); 
                   } 
               }) 
               .observeOn(Schedulers.computation()) 
               .map(new Func1() {
                  @Override
                  public String call(String s) {
                       Log.d("lqm","3map:"+android.os.Process.myTid()); 
                       return s.concat(" map3 "); 
                   } 
                }) 
               .subscribeOn(Schedulers.io()) 
               .observeOn(AndroidSchedulers.mainThread()) 
               .subscribe(new Action1() { 
                     @Override
                     public void call(String s) {          
                         Log.d("lqm","call:"+android.os.Process.myTid()); 
                      } 
               }); 
}
11-19 23:39:35.815 19573-19573/pa.test.com.testapp D/lqm: mainthread :19573
11-19 23:39:35.845 19573-20402/pa.test.com.testapp D/lqm: flatMap:20402
11-19 23:39:35.855 19573-20402/pa.test.com.testapp D/lqm: filter:20402
11-19 23:39:35.855 19573-20404/pa.test.com.testapp D/lqm: 1map:20404
11-19 23:39:35.855 19573-20404/pa.test.com.testapp D/lqm: 2map:20404
11-19 23:39:35.855 19573-20403/pa.test.com.testapp D/lqm: 3map:20403
11-19 23:39:35.885 19573-19573/pa.test.com.testapp D/lqm: call:19573

嗯,对比下结果,再看下上面那段话,是不是明白了很多。
这边要注意下,不同于 observeOn() , subscribeOn() 的位置放在哪里都可以,但它是只能调用一次的

那如果调多次,会有什么样的结果呢?

private void observableEvent() { 
     Log.d("lqm","mainthread :"+android.os.Process.myTid()); 
     Observable.just(1) 
               .subscribeOn(Schedulers.io()) 
               .map(new Func1() { 
                   @Override 
                   public String call(Integer integer) { 
                         Log.d("lqm","map:"+android.os.Process.myTid()); 
                         return integer+"a"; 
                    } 
                }) 
                .filter(new Func1() { 
                    @Override 
                    public Boolean call(String s) { 
                          Log.d("lqm","filter :"+android.os.Process.myTid()); 
                          return s.contains("1"); 
                     } 
                }) 
                .subscribeOn(Schedulers.computation()) 
                .subscribe(new Action1() {
                       @Override 
                       public void call(String s) {
                            Log.d("lqm","onNext:"+android.os.Process.myTid()); 
                       } 
           }); 
}
11-19 23:43:21.505 23679-23679/pa.test.com.testapp D/lqm: mainthread :23679
11-19 23:43:21.535 23679-24467/pa.test.com.testapp D/lqm: map:24467
11-19 23:43:21.535 23679-24467/pa.test.com.testapp D/lqm: filter :24467
11-19 23:43:21.535 23679-24467/pa.test.com.testapp D/lqm: onNext:24467

可以看出,第二次subscribeOn(Schedulers.computation())完全没有影响线程运行的改变。所以第二次subscribeOn()是无作用的

讲到这里,关于Android-RxJava 常见API使用以及线程转换要点,已经接近尾声,当然后续会继续深入其原理层的东西,请大家持续关注。

如果觉得此文不错,麻烦帮我点下“喜欢”。么么哒!

你可能感兴趣的:(Android-RxJava 常见API使用以及线程转换要点)