RxJava和RxAndroid

RxJava介绍

首先要说明的一点,RxAndroid和RxJava是差不多的东西,只不过RxAndroid 针对Android平台做了一点调整。那么RxJava是什么?在其github上是这样讲的:一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库。这么讲可能还有点绕口,简单的讲实际上最重要的就是异步两字,RxJava可以简单的实现异步操作,并且不管逻辑多么复杂,它始终能够保持简洁性。
通常在Android中,非UI线程是不能更新UI界面的,而一些耗时的操作我们又不能放在UI线程,否则会导致界面卡顿。这种情况下,我们就需要切换线程来实现,即Handler和AsyncTask来实现,但是这两种都有个缺陷,代码非常多,非常杂,可读性非常差。所以,RxJava出现了,它能够两行代码就实现线程切换,非常的简单,使用起来就会让人感觉很爽,再也不用为异步操作写如此繁重的代码了。

RxJava基本用法

RxJava最核心的两个东西是Observables(被观察者,事件源)和Observer/Subscriber(观察者),还有将他们联系在一起的操作subscribe(订阅)。当被观察者发生变化时观察者能即使做出相应,就好像我们的按钮事件一样:

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

在这里button就是被观察者,OnClickListener就是观察者,setOnClickListener这个方法就相当于订阅操作,当button被按下时,OnClickListener监听到变化,调用OnClick做出反应,RxJava实现的就是类似这样的一个过程。注意这里的观察者有两种Observer,Subscriber,这两个其实是差不多的,Subscriber是对Observer的一种扩展,内部增加了OnStart方法,在事件未发送之前订阅,用于做一些准备工作,并且还有unsubscribe()用于取消订阅。
让我们来看一下ObServer的内部实现:

public interface Observer<T> {

    void onCompleted();

    void onError(Throwable e);

    void onNext(T t);

}

可以看到ObServer本身是一个接口,内部有onNext(T t)方法:观测到所检测的被观察者有变化时做出相应反应。onCompleted()方法:RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。onCompleted():事件队列发生异常,要调用的方法。我们在定义一个观察者的时候,需要实现这些方法,来完成事件队列。
观察者有了,那么被观察者Observables怎么创建呢,RxJava提供了一系列操作符供我们调用,其中就有很多创建型操作符,举个例子,创建一个Observables,发出hello world字符串给观察者:

Observable<String> myObservable = Observable.create(  
    new Observable.OnSubscribe<String>() {  
        @Override  
        public void call(Subscriber<? super String> sub) {  
            sub.onNext("Hello, world!");  
            sub.onCompleted();  
        }  
    }  
);  

既然有了Observables,那我们就可以根据这个Observables创建一个观察者了,如下:

 Observer<String> TestObserver=new Observer<String>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(String s) {
                Log.i(TAG,s);
        }
    }

这样我们就可以愉快的订阅了:

myObservable.subscribe(TestObserver);

这样,一个简单的RxJava订阅流程就完成了。这里可能很多人就有疑问了,关键的异步呢,体现在哪了?其实这个例子可能不是很明显,因为被观察者并不是一个耗时线程,不能很直观的体现异步。如果myObservable这是一个异步任务,比如网络请求,那么我们订阅之后,TestObserver会一直监听myObservable是否有返回,如果有,那么就做出响应,本质是一样的。

RxJava的操作符

RxJava一个强大的地方在于它的异步,另外一个强大的地方就在于它提供了强大的操作符支持。这里说明一下几个常用的操作符:

  • ceate操作符
Observable<String> myObservable = Observable.create(  
    new Observable.OnSubscribe<String>() {  
        @Override  
        public void call(Subscriber<? super String> sub) {  
            sub.onNext("Hello, world!");  
            sub.onCompleted();  
        }  
    }  
);

ceate操作符创建一个被观察者,在call方法里持有一个观察者Subscriber参数,当这个Observable被订阅时,执行观察者相应的方法。

  • just操作符
Observable<String> myObservable = Observable.just("Hello, world!");  

上面的代码可以用这一句话,代替。just操作符的功能就是将一个对象转化为Observable。

  • from操作符
Observable<String> myObservable = Observable.from("Hello"," world!");  

既然有了将单一对象转化为Observable的操作符,那么必须要有将多个对象转化为Observable的操作符,那就是from,from接收一个对象数组,然后逐一发射给观察者。

现在,用一个例子来说明其他操作符,比如我们有这样一个方法,根据学生姓名关键字查询学生列表,返回一个Observable。

Observable<List<Student>> query(String name); 

然后我们的需求是一个一个的输出学生姓名,实现如下:

query("王").subscribe(list -> {
for(Student student:list){
      Log.i(TAG,student.getName());
});

  • flatMap操作符
query("王").flatMap(list -> Observable.from(list)) 
                 .subscribe(student ->Log.i(TAG,student.getName());
);

上面的例子用flatMap操作符,就可以变得很简洁,flatMap操作符的功能是接收一个接收一个Observable的输出作为输入,同时输出另外一个Observable,通常是接收一个list,然后逐一发送list的元素。比如这边的Student数组,变成了逐一发送student的Observable。

  • Map操作符
query("王").flatMap(list -> Observable.from(list)) 
                  .Map(student->return student.getGrade())
                 .subscribe(grade->Log.i(TAG,grade+"");
);

现在我们只想输出每个学生的成绩,我们就需要Map操作符,它的功能是接收一种类型的Observable,转化为另外一种Observable,比如这边的Student类型转化为了Int型的Observable。

query("王").flatMap(list -> Observable.from(list)) 
                  .Map(student->return student.getGrade())
                 .subscribe(grade->Log.i(TAG,grade+"");
);

  • filter操作符
query("王").flatMap(list -> Observable.from(list)) 
                  .Map(student->return student.getGrade())
                  .filter(grade->grade>80)
                 .subscribe(grade->Log.i(TAG,grade+"");
);

顾名思义filter操作符就是过滤用的,相当于加个判断条件,比如这边的就是加上分数大于80的条件.

  • take操作符
query("王").flatMap(list -> Observable.from(list)) 
                  .Map(student->return student.getGrade())
                  .filter(grade->grade>80)
                  .take(5)
                 .subscribe(grade->Log.i(TAG,grade+"");
);

take操作符的功能是限定个数,比如这边的功能就是限定我最多需要5个成绩。

  • doOnNext操作符
query("王").flatMap(list -> Observable.from(list)) 
                  .Map(student->return student.getGrade())
                  .filter(grade->grade>80)
                  .take(5)
                  .doOnNext(grade->save(grade))
                 .subscribe(grade->Log.i(TAG,grade+"");
);

doOnNext()允许我们在每次输出一个元素之前做一些额外的事情,比如这里的我们用来保存成绩。

  • subscribeOn/observeOn操作符
query("王").flatMap(list -> Observable.from(list)) 
                  .Map(student->return student.getGrade())
                  .filter(grade->grade>80)
                  .take(5)
                  .doOnNext(grade->save(grade))
                  .subscribeOn(Schedulers.io())
                  .observeOn(AndroidSchedulers.mainThread())
                 .subscribe(grade->Log.i(TAG,grade+"");
);

这两个操作符一般都是成对出现的,他们的功能就是切换线程。subscribeOn是指定被观察者的线程,observeOn是指定观察者的线程。比如这个例子中前面的订阅的工作在IO线程做,后面的打印功能在主线程做。

  • 小结
    怎么样,看起来我好像做了很多事情,又有判断数据,又有保存数据,又有选取数据,关键还有线程切换,然而,我实际上就写了那么一点代码,看起来是不是酷!这就是RxJava的魅力所在。

RxAndroid

一开始说了,RxAndroid其实跟RxJava是差不多的,但是总归还是有一点变化的。比如Android上会有生命周期的问题,可能会导致内存泄漏:Observable持有Context导致的内存泄露。在这个问题上,我们的解决方法是这样的:

private Subscription mTestSubscription= Subscriptions.empty();

public void test(){
mTestSubscription=myObservable.subscribe(TestObserver);
}
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mTestSubscription != null && !mTestSubscription.isUnsubscribed())        {
            mTestSubscription.unsubscribe();
        }

    }

就是在订阅的时候,用一个Subscription来保存它,然后在退出这个Activity的时候取消订阅。
另外还有一些专门为Android设计的RxView,比如以下防抖动的View:

RxView.clicks(btn_click)
        .throttleFirst(3, TimeUnit.SECONDS)
        .subscribe();

参考:https://www.jianshu.com/p/d9fca152017b

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

推荐阅读更多精彩内容