RXJava入门

来源:互联网 发布:淘宝网齐峰堂足宝粉 编辑:程序博客网 时间:2024/06/07 03:34
第一个问题 RxJava 是什么?
RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。
有点抽象,我们抓住关键词 异步,基于事件
那么我们可以这用认为 RxJava 是一种能执行异步操作 封装好的一套逻辑
在这里先说一下,RxJava 采用的是扩展的观察者模式

第二个问题RxJava 好在哪里?
换句话说,『同样是做异步,为什么人们用它,而不用现成的 AsyncTask / Handler / XXX / ... ?』
因为RxJava 简洁,随着程序逻辑变得越来越复杂,它依然能够保持简洁。
自己慢慢体会 RxJava 的好处吧 在这里我就不多说了

三.前面提到了扩展的观察者模式,下面我们来说一下扩展者观察者模式
我们所理解的观察者模式: 一个人监督另一个人 就像侦查兵

在编程中的观察者模式: 有两个部分,观察者,被观察者
当被观察者改变时,通知观察者做出响应
Android 开发中一个比较典型的例子是点击监听器 OnClickListener 。对设置OnClickListener 来说, View 是被观察者, OnClickListener 是观察者,二者通过 setOnClickListener() 方法达成订阅关系。订阅之后用户点击按钮的瞬间,Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。

四.现在我们有了一定基础 下面我们开始RxJava的讲解
首先Rxjava 的核心类
Observer(观察者),Observable (可观察者,即被观察者)、  subscribe (订阅)
Subscribers是Observer的实现类
RxJava最核心的两个东西是Observables(被观察者,事件源)和Subscribers(观察者)。Observables发出一系列事件,Subscribers处理这些事件。这里的事件可以是任何你感兴趣的东西(触摸事件,web接口调用返回的数据。。。)

一个Observable可以发出零个或者多个事件,知道结束或者出错。每发出一个事件,就会调用它的Subscriber的onNext方法,最后调用Subscriber.onNext()或者Subscriber.onError()结束。

下面我们来看一下简单的使用
创建一个Observable对象很简单,直接调用Observable.create即可
这里定义的Observable对象仅仅发出一个Hello World字符串,然后就结束了
[java] view plain copy
  1. Observable<String> myObservable = Observable.create(  
  2.     new Observable.OnSubscribe<String>() {  
  3.         @Override  
  4.         public void call(Subscriber<? super String> sub) { 
  5. //可以理解为 通知了观察者 
  6.             sub.onNext("Hello, world!");  
  7.             sub.onCompleted();  
  8.         }  
  9.     }  
  10. );  
接着我们创建一个Subscriber来处理Observable对象发出的字符串

这里subscriber仅仅就是打印observable发出的字符串。
  1. Subscriber<String> mySubscriber = new Subscriber<String>() {  
//获得了传过来的值
  1.     @Override  
  2.     public void onNext(String s) { System.out.println(s); }  
  3.   
  4.     @Override  
  5.     public void onCompleted() { }  
  6.   
  7.     @Override  
  8.     public void onError(Throwable e) { }  
  9. };  

//最后形成订阅关系
myObservable.subscribe(mySubscriber);  

那么实现被观察者还有几种方式 我们来看一下
1.
Observable myObservable = Observable.just("Hello");// 将会依次调用:// onNext("Hello");// onCompleted();
2.
String[] words = {"Hello"};Observable observable = Observable.from(words);// 将会依次调用:// onNext("Hello");// onCompleted();

五.除了 subscribe(Observer) 和 subscribe(Subscriber) ,subscribe() 还支持不完整定义的回调,RxJava 会自动根据定义创建出Subscriber 。形式如下:
Action1<String> onNextAction = new Action1<String>() {
// onNext()  
@Override  
public void call(String s) {
Log.d(tag, s);  
}
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
// onError()  
@Override  
public void call(Throwable throwable) {
// Error handling }
};
Action0 onCompletedAction = new Action0() { 
// onCompleted()  
@Override  
public void call() { 
Log.d(tag, "completed");  
}
};
// 自动创建 Subscriber ,并使用 onNextAction 来定义 
onNext()observable.subscribe(onNextAction);
// 自动创建 Subscriber ,并使用 
onNextAction 和 onErrorAction 来定义 onNext() 和 onError()observable.subscribe(onNextAction, onErrorAction);
// 自动创建 Subscriber ,并使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted()observable.subscribe(onNextAction, onErrorAction, onCompletedAction);
简单解释一下这段代码中出现的 Action1 和 Action0
 Action0 是 RxJava 的一个接口,它只有一个方法 call(),这个方法是无参无返回值的;由于 onCompleted() 方法也是无参无返回值的,因此 Action0 可以被当成一个包装对象,将 onCompleted() 的内容打包起来将自己作为一个参数传入 subscribe() 以实现不完整定义的回调。这样其实也可以看做将 onCompleted() 方法作为参数传进了subscribe(),相当于其他某些语言中的『闭包』。
 Action1 也是一个接口,它同样只有一个方法 call(T param),这个方法也无返回值,但有一个参数;与 Action0 同理,由于 onNext(T obj) 和 onError(Throwable error) 也是单参数无返回值的,因此 Action1 可以将onNext(obj) 和 onError(error) 打包起来传入 subscribe() 以实现不完整定义的回调。

六.RxJava 有关线程的问题
到此我们可能有这样的疑问,观察者和被观察者 分别在哪个线程中呢?
如果都在主线程 哪算什么异步?

在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)。

使用 subscribeOn()
subscribeOn(): 指定subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程

observeOn() 
 observeOn(): 指定Subscriber 所运行在的线程。或者叫做事件消费的线程。

那么这两方法中都可以传入那些参数呢?
  • 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 主线程运行。
简单的看一下使用
Observable.just(1, 2, 3, 4).subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程

//订阅观察者
//Action1.subscribe(new Action1<Integer>() { 
@Override 
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
}
);

七.Rxjava中的变换
所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列
概念比较抽象:下面我们来看一些例子

Observable.just("images/logo.png")
// 输入类型 String.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String filePath) {// 参数类型
String return getBitmapFromPath(filePath); // 返回类型 Bitmap
}
}
).subscribe(new Action1<Bitmap>() {
@Override 
public void call(Bitmap bitmap) { // 参数类型 Bitmap
showBitmap(bitmap);
}
}
);
Func1 这个类是变换功能的核心API
map(): 事件对象的直接变换,具体功能上面已经介绍过。它是 RxJava 最常用的变换。
这里出现了一个叫做 Func1 的类。它和 Action1 非常相似,也是 RxJava 的一个接口,用于包装含有一个参数的方法。 Func1 和 Action的区别在于, Func1 包装的是有返回值的方法。另外,和 ActionX 一样, FuncX 也有多个,用于不同参数个数的方法。FuncX 和ActionX 的区别在 FuncX 包装的是有返回值的方法。

在转换中还有一个方法flatMap()
目前用到的最多的就是将一个集合转换成单个的对象,返回给观察者的是所有的对象,这就不需要我们手动的遍历了
看一下例子
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
//将集合转换成了单个的对象
.flatMap(new Func1<List<DataObj>, Observable<DataObj>>() {
@Override
public Observable<DataObj> call(List<DataObj> dataObjs) {
//返回给观察者
return Observable.from(dataObjs);
}
}).subscribe(new Observer<DataObj>() {
@Override
public void onCompleted() {

}

@Override
public void onError(Throwable e) {

}

@Override
public void onNext(DataObj dataObj) {
//不需要遍历就能拿到所有的对象
String login = dataObj.getLogin();
Log.i("xxx", "login:" + login);


}
});














0 0