对于Android开发来说, RxJava应该是一个非常流行的框架了。配合Retrofit处理网络请求非常方便。最近正好有时间,学习了一下RxJava的原理,在此总结一下。
我理解的RxJava原理
RxJava的核心原理其实就是典型的响应者模式,这并不难,但是它很巧妙的把这种响应者模式进行了链式的连接,这应该就是一种响应式编程的方式了吧。我把整个学习过程分成了三步,一步一步解密RxJava(代码尽量贴近RxJava源码)。同时为了练习Kotlin,因此决定用Kotlin来进行书写。
第一步:基础
首先声明一个观察者接口Observer:
interface Observer {
fun onComplete()
fun onError(t:Throwable)
fun onNext(t:T)
}
再声明一个订阅者Subscriber实现观察者接口对观察者进行扩展:
abstract class Subscriber:Observer{
/*省略了一大堆其它的方法,用这一个方法来代替它们*/
fun onStart() {}
}
观察者齐全了,我们需要被观察者Observable了(该类也是整个RxJava的核心所在,所有的操作符,线程调度的逻辑其实都在这里)
class Observable constructor(val onSubscribe: OnSubscribe){
companion object{
/**
* 返回一个带有OnSubscribe接口实例的Observable对象
* */
fun create(onSubscribe: OnSubscribe):Observable{
return Observable(onSubscribe)
}
}
/**
*订阅方法:实例化观察者并且可以向该观察者发送消息了
* in T表示泛型中的消费者 相当于Java中的 ? super T(T以及T的父类)
* out T表示泛型中的生产者 相当于Java中的 ? extends T(T以及T的子类)
* */
fun subscribe(subscriber: Subscriber){
subscriber.onStart()
onSubscribe.call(subscriber)
}
//订阅接口
interface OnSubscribe {
/**
* 把观察者传入被观察者中
* */
fun call(subscriber:Subscriber)
}
}
OK,RxJava的基础分析结束了,就是这么多,现在可以进行最基本的RxJava功能了
Observable.create(object : Observable.OnSubscribe{//记住这种匿名内部类写法
override fun call(subscriber: Subscriber) {
subscriber.onNext("123456")
}
}).subscribe(object : Subscriber(){
override fun onComplete() {
}
override fun onError(t: Throwable) {
}
override fun onNext(t: String) {
Toast.makeText(this@MainActivity,t,Toast.LENGTH_SHORT).show()
}
})
第二步:操作符 (第二步开始主要说明逻辑,齐全的项目代码会在文后的链接中)
RxJava真正的魅力就在于它丰富的操作符和线程调度,现在我们来用map操作符举例,看它是如何实现的:
interface Transformer{//把T类型转换成R类型的接口
fun transform(t:T):R
}
/*
* 每次的操作符都会默认内部生成一个观察者
* 在call方法里去订阅调用操作符的被观察者,
* 并且返回一个新的被观察者以让下一个观察者可以订阅,
* 这样整条逻辑链就被连接起来了
*/
fun map(transformer: Transformer):Observable{
return create(object :OnSubscribe{
override fun call(subscriber: Subscriber) {
this@Observable.subscribe(object : Subscriber(){//这行是操作符能全部连接起来的关键
override fun onComplete() {
}
override fun onError(t: Throwable) {
}
override fun onNext(t: T) {
subscriber.onNext(transformer.transform(t))
}
})
}
})
}
map操作符实现了。看!其实它不难,但是里面的思想很精华。接下来就要思考如果所有的操作符逻辑都写在这个Observable类里,那这耦合性简直了...所以我们需要解耦
/*MapOnSubscribe(代替OnSubscribe接口的功能) MapSubscriber(代替Map中
默认生成的Subscriber对象)
*/
/**
* 解耦后的Map方法
* */
fun map_(transformer: Transformer):Observable{
return create(MapOnSubscribe(this@Observable,transformer))
}
好的,Map分析完毕。接下来是RxJava的线程调度了......
第三步:线程调度
RxJava中的线程调度分为subscribeOn方法和observeOn两种方法,subscribeOn作用于它前面的代码逻辑,且只有第一个有效,observeOn作用于它后面的代码逻辑,每次的都有效,当然说了算的也肯定是最后一个observeOn方法嘛。
/**
* subscribeOn方法调度函数线程
* */
fun subscribeOn(scheduler: Scheduler):Observable{
return create(object : OnSubscribe{
override fun call(subscriber: Subscriber) {
/*这里this@Observable.subscribe()方法的subscriber参数就是最后的观察者对象。调用的任何一个subscribeOn方法
*都会把该对象往前(上)传,所以最终决定该对象到底在哪个线程执行的subscribeOn
* 方法就是第一个,因此其它的subscribeOn方法无效
* */
scheduler.createWorker().schedule(Runnable {this@Observable.subscribe(subscriber)})
}
})
}
/**
* observeOn方法调度函数线程
* */
fun observeOn(scheduler: Scheduler):Observable{
return create(object : OnSubscribe{
override fun call(subscriber: Subscriber) {
val worker = scheduler.createWorker()
/*注意这里this@Observable.subscribe的方法参数则是我们自己建立的Subscriber对象,
实际的最后观察者会在这里被切换到不同的线程中操作。当然有最后决定权的observeOn
就是最后一个observeOn方法。
* */
this@Observable.subscribe(object : Subscriber(){
override fun onComplete() {
worker.schedule(java.lang.Runnable { subscriber.onComplete() })
}
override fun onError(t: Throwable) {
worker.schedule(java.lang.Runnable { subscriber.onError(t) })
}
override fun onNext(t: T) {
worker.schedule(java.lang.Runnable { subscriber.onNext(t) })
}
})
}
})
}
贴出的代码中都有注释说明,所以也就不废话了。这是最后带有操作符和线程调度的调用方法:
Observable.create(object : Observable.OnSubscribe{
override fun call(subscriber: Subscriber) {
subscriber.onNext(123456)
}
}).subscribeOn(Schedulers.io()).map_(object : Observable.Transformer{
override fun transform(t: Int): String {
return "发射消息"+t
}
}).observeOn(Schedulers.main()).subscribe(object : Subscriber(){
override fun onComplete() {
}
override fun onError(t: Throwable) {
}
override fun onNext(t: String) {
Toast.makeText(this@MainActivity,t,Toast.LENGTH_SHORT).show()
}
})
最后附上项目的下载地址(项目不大,仅供学习):
https://github.com/hong890823/HongRxKotlin