我们都知道不管RxJava1还是2都是以观察者模式为其核心。然而如果仅仅运用观察者模式RxJava 势必不能大行其道。灵活的线程变换是RxJava的另一个核心功能。如果把观察者模式是RxJava的躯体,那么线程变换就是RxJava的血脉,负责控制血液运行的管道。
在了解RxJava线程变化之前你我们得了解RxJava大体的使用方式和一些体系结构,并达成一个共识:即通常的绝大部分操作符运行之后都会产生一个新的Observable对象,新的Observable对象也会订阅一个与之匹配的Observer对象。
我们这里只关注subscribeOn()和observeOn()是如何启动线程变换作用的。
在讲述其变换之前我们先实践一下,即抛开RxJava,简单实现观察者模式和线程变换,我们暂且叫他RxJavaLike !!
直接上代码:
1.首先在Activity中提供一个打印log的功能,打印出代码执行的线程+数据:
private void log(String msg) {
Log.d(getTAG(),"线程="+ Thread.currentThread().getName() + " Msg=" + msg);
}
2.提供一个Function接口,负责处理数据源。
public interface Function {
R apply(T t);
}
3.提供一个简单的被观察者,主要的方法就是触发订阅subscribe,使用Function对象处理数据源完毕后把结果交给观察者处理。见 subscribe(Observerpublic class Observable {
private T data;
private Function transfer;
public Observable() {
}
public Observable(T data, Function transfer) {
this.data = data;
this.transfer = transfer;
}
public void subscribe(Observer observer) {
R real = transfer.apply(data);
observer.onSubscribe(real);
}
}
4.观察者接口类提供一个触发订阅的方法,负责处理经由被观察者处理过的数据流。
public interface Observer {
void onSubscribe(T data);
}
5.这样一个简单的观察者模式就形成了。也是第一个例子:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Observable<>("10", new Function() {
@Override
public Integer apply(String s) {
log("apply " + s);
return Integer.parseInt(s) + 10;
}
}).subscribe(new Observer() {
@Override
public void onSubscribe(Integer data) {
log("onSubscribe " + data.toString());
}
});
}
打印的结果如下:
D/ProxyActivity: 线程=main Mgs=apply 10
D/ProxyActivity: 线程=main Mgs=onSubscribe 20
这样一个简单的观察者模式,及其使用就算完成了。然而这并没有什么卵用。我们要的线程变换呢?
6.那在这个小例子的基础上改改。实现一个数据处理在子线程、数据订阅在主线程。也就是第二个例子。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new Runnable() {
@Override
public void run() {
Observer realObserver = new Observer() {
@Override
public void onSubscribe(Integer data) {
log("onSubscribe " + data.toString());
}
};
new Observable<>("10", new Function() {
@Override
public Integer apply(String s) {
log("apply " + s);
return Integer.parseInt(s) + 10;
}
}).subscribe(new ProxyObserver<>(realObserver));
}
}).start();
}
代理ProxyObserver负责订阅发生时,先进行线程变换。
public static final class ProxyObserver implements Observer {
private final Observer real;
public ProxyObserver(Observer real) {
this.real = real;
}
@Override
public void onSubscribe(final T data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
real.onSubscribe(data);
}
});
}
}
打印的结果如下:
D/ProxyActivity: 线程=Thread-3 Mgs=apply 10
D/ProxyActivity: 线程=main Mgs=onSubscribe 21
这样就实现了我们简单的需求,数据处理发生在子线程,数据订阅回调在主线程。
然而你可能会问你搞毛啊,这什么乱七八糟的。new Thread()都上来了。说好的RxJavaLike呢,这一点都不像~
呗急,好歹这也实现了线程变换撒。我们着重关注一下主线程的切换,一个简单的代理模式完成了,我要说的是RxJava也是通过这种简单的代理模式实现的通用的线程变换。
其中啊 RxJava2 subscribeOn()方法是通过代理模式包裹着原Observable对象在触发subscribe()时-注释(真实发生在subscribeActual()方法中),进行触发订阅线程切换。在observeOn()时形成代理Subscriber对象(形同Observer)如上述代码 ProxyObserver 一样进行了数据观测线程的切换。
RxJava1 subscribeOn()方法干脆把原Observable对象当成数据源向新的代理Subscriber对象中发射,在代理对象Subscriber的 onNext()方法中进行线程变换,其原理和上述ProxyObserver主线程切换的道理是一样的。
了解了这些后,我们也使用代理模式在上述代码的基础上,提供2个操作符subscribeOnIO()和observeOnMain(),每次操作符生成新的Observable对象,包裹原Observable对象,在订阅发生时,进行线程切换。在数据处理完毕后对观测线程进行切换。
7.于是我们修改了Observable,增加2个方法(操作符)。
public class Observable {
private T data;
private Function transfer;
public Observable() {
}
public Observable(T data, Function transfer) {
this.data = data;
this.transfer = transfer;
}
public void subscribe(Observer observer) {
R real = transfer.apply(data);
observer.onSubscribe(real);
}
public Observable subscribeOnIO() {
return new ObservableIO<>(this);
}
public Observable observeOnMain() {
return new ObservableMain<>(this);
}
}
并且增加了2个类,都继承Observable:
ObservableIO负责在订阅时,即数据处理的过程,将线程切换到子线程。
public class ObservableIO extends Observable {
private Observable real;
public ObservableIO(Observable real) {
this.real = real;
}
@Override
public void subscribe(final Observer observer) {
ThreadPools.newThread(new Runnable() {
@Override
public void run() {
real.subscribe(observer);
}
}).start();
}
}
ObservableMain包裹原Observable对象 和代理ProxyObserver 负责包裹observer对象,并在数据处理完毕后、观测发生前将线程切换到主线程。蓝后将处理过的数据交给观察者。
public class ObservableMain extends Observable {
private Observable real;
public ObservableMain(Observable real) {
this.real = real;
}
@Override
public void subscribe(Observer observer) {
real.subscribe(new ProxyObserver<>(observer));
}
public static final class ProxyObserver implements Observer {
private final Observer real;
public ProxyObserver(Observer real) {
this.real = real;
}
@Override
public void onSubscribe(final R data) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
real.onSubscribe(data);
}
});
}
}
}
于是原来的例子就变成了这样。也就是第三个例子。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Observable<>("10", new Function() {
@Override
public Integer apply(String s) {
log("apply " + s);
return Integer.parseInt(s) + 10;
}
}).subscribeOnIO()
.observeOnMain()
.subscribe(new Observer() {
@Override
public void onSubscribe(Integer data) {
log("onSubscribe " + data.toString());
}
});
}
打印的结果如下:
D/ProxyActivity: 线程=TaskThread #1 Mgs=apply 10
D/ProxyActivity: 线程=main Mgs=onSubscribe 20
这样我们的例子多多少少长的就有点像RxJava了 Like~~
当然了RxJava不同于我们的例子。例子里只是简单的将数据处理切换到子线程、数据观测切换到主线程。RxJava将线程处理交给Scheduler提供了更加通用的线程处理。
好了,在例子的基础上我们在总结一下RxJava的线程变换:
1、绝大多数操作符运行之后都会生成一个新的Observable对象,这个新的Observable通常把原Observable作为其成员变量也就是包裹着原Observable对象。
2、数据处理的线程变换发生在新Observable subscribeActual()方法内。数据观测的线程变换利用代理模式,形成新的Subscriber对象代理旧的Subscriber对象,并把订阅的数据切换线程后交给旧的Subscriber对象来处理从而达到线程变换的目的。