RxJava初探

转载自:http://codethink.me/2015/05/09/intro-of-rxjava/

1.前言

本文主要记录了初步学习RxJava后的总结,希望用最短的篇幅讲清楚RxJava的主要用法。部分内容来自Dan Lew的Grokking RxJava
本文的示例代码在这里

2 基本概念

2.1 Rx结构
响应式编程的主要组成部分是observable, operator和susbscriber(与Dan Lew的文章不同,这里把Operator也做为组成部分介绍,这样对结构的整体性会有更全面的认识)。一般响应式编程的信息流如下所示:

Observable -> Operator 1 -> Operator 2 -> Operator 3 -> Subscriber
也就是说,observable是事件的生产者,subscriber是事件最终的消费者。
因为subscriber通常在主线程中执行,因此设计上要求其代码尽可能简单,只对事件进行响应,而修改事件的工作全部由operator执行。
2.2 最简单的模式
如果我们不需要修改事件,就不需要在observable和subscriber中插入operator。这时的Rx结构如下:
Obsevable -> Subscriber
这看起来很像设计模式中的观察者模式,他们最重要的区别之一在于在没有subscriber之前,observable不会产生事件。
一个简单的RxJava HelloWorld的代码如下。

// 创建observable
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {    
@Override    
public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("Hello RxJava");
        subscriber.onCompleted();
    }
});

// 创建subscriber
Subscriber<String> subscriber = new Subscriber<String>() {    
@Override    
public void onCompleted() {    
}    
@Override    
public void onError(Throwable e) {    
}    
@Override    
public void onNext(String s) {        
    log(s);    
 }
};
 
// 订阅
observable.subscribe(subscriber);

这里的代码对于一句简单的HelloWorld的而言太繁琐了。因此,RxJava提供了一些简化的方法。
首先是创建observable,如果我们只需要发送一个事件(这里的事件是字符串”Hellow RxJava”),我们可以使用Observable类的just方法,简化后的代码如下

// 创建observable
Observable<String> observable = Observable.just("Hello RxJava");

同样,如果我们不关心subscriber是否结束(onComplete())或者发生错误(onError()),subscriber的代码可以简化为

// 创建subscriber
Action1<String> subscriber = new Action1<String>() {    
@Override    
public void call(String s) {
        log(s);
    }
};

我们直接把创建和订阅连接起来,完整的代码如下。

Observable.just("Hello RxJava").subscribe(new Action1<String>() {    
@Override    
public void call(String s) {
        log(s);
    }
});

最后,使用Java 8的lambda(Android上可以使用Retrolambda),这个HelloWorld的最终版本如下:

Observable.just("Hello RxJava")
    .subscribe(s -> log(s));

2.3 加入operator
很多时候,我们需要针对处理过的事件做出响应,而不仅仅是Observable产生的原始事件。由于1.1中阐述的原因,这里就需要引入operator来处理原始事件。
这里以一个极简单的Markdown处理为例:假设输入的是Markdown格式的文件,最终展示文字的是一个WebView,这里就需要引入一个将Markdown转为HTML的operator,其代码如下:

Observable.just("#Basic Markdown to HTML").map(new Func1<String, String>() {    
@Override    
public String call(String s) {
        if(s != null && s.startsWith("#")) {
            return "<h1>" + s.substring(1, s.length()) + "</h1>";
        }
        return null;
    }
}).subscribe(s -> log(s));

这里使用了名为map()的operator,它的作用很简单,就是接收一个事件,并返回处理后的事件。Func1的第一个泛型参数表示输入类型,第二个繁星参数表示返回类型。
我们这里同样可以采用lambda来简化代码,简化后的代码如下:

Observable.just("#Basic Markdown to HTML with lambda")
       .map(s -> s != null && s.startsWith("#") ? "<h1>" + s.substring(1, s.length()) + "</h1>" : null)
        .subscribe(s -> log(s));

2.4 Subscription
前三小节有意隐藏了RxJava的一个细节,实 际上执行Observable.subscribe()时,它会返回一个Subscrition,它代表了Observable和Subscriber之 间的关系。你可以通过Subscrition解除Observable和Subscriber之间的订阅关系,并立即停止执行整个订阅链。示例代码如下:

Subscription subscription = Observable.just("Unsubscribe me later").subscribe(s -> log(s));
subscription.unsubscribe();
log("isSubscribed = " + subscription.isUnsubscribed());

3 多线程

在开发过程中,为了避免阻塞UI线程,我们可能需要将某些工作放到指定线程执行。在 RxJava中,你可以通过subscribeOn()来指定Observer的运行线程,通过observeOn()指定Subscriber的运行线 程。这两个方法都是operator,因此它们可以像所有operator那样作用于任何的Observable。一个简单的例子如下:

Observable.create(new Observable.OnSubscribe<String>() {    
@Override    
public void call(Subscriber<? super String> subscriber) {
        log("Observable on Thread -> " + Thread.currentThread().getName());
        subscriber.onNext("MultiThreading");
        subscriber.onCompleted();
    }
}).subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(s -> {
            log("Subscriber on Thread -> " + Thread.currentThread().getName());
     });

4 错误处理

RxJava使用Subscriber的onError()进行错误处理。每一个 Obervable的执行最后一定会调用onCompleted()和onError()方法中的一个。相比于传统的回调处理错误的方式,订阅链中任何时 候出现的错误,都只需要在Subscriber的onError()方法中处理,operator不需要处理异常。

5 小结

相比于Otto这种总线式的处理方式,RxJava对于订阅事件的处理更精细。同时,它还引入了许 多函数式编程的特性,对于信息流处理有更好的解耦。目前只是通过阅读以及一些玩具代码初步了解了其用法,这仅仅是个开始。希望在实际项目中使用后,能有时 间总结诸如自定义Operator等更多的高级用法。
参考
Grokking RxJava

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容