从案例学RxAndroid开发(上)

原文连接:RxAndroid Basics: Part 1java

若是你在阅读这篇文章,相信你必定很想了解RxJava以及如何在Android应用中使用它。可能你已经见过RxJava的代码了,但仍然有些疑惑,愿你能在这篇文章里找到答案。android

当我第一次使用RxJava的时候我只是在照搬代码,这些代码能跑起来,可是我对RxJava的基础部分仍然存在误解,并且我找不到好的源码来学习。因此为了理解RxJava,我不得不一点一点学习,踩了很多坑。git

为了避免让你把我踩过的坑再踩一遍,我会基于个人学习成果写一些例子出来,目的就是让你可以对RxJava有足够的了解,并能在你的Android应用中使用它。github

源码能够在这里找到。在每一个例子的开始,我会写清每一个代码段是属于哪一个Activity的。我会将本文分为两个部分,在第一部分里,我会着重讲解如何用RxJava异步加载数据;在第二部分里,我会探索一些更高级的用法。网络

几个概念

在开始说代码以前,先澄清几个概念。RxJava最核心的东西就是Observable和Observer。Observable会发出数据,而与之相对的Observer则会经过订阅Observable来进行观察。多线程

Observer能够在Observable发出数据、报错或者声明没有数据能够发送时进行相应的操做。这三个操做被封装在Observer接口中,相应的方法为onNext(),onError()和onCompleted()。app

明确了这些概念之后,让咱们来看一些例子。异步

案例1:基础

如今要写一个用来展现一个颜色列表的Activity。咱们要写一个能发送一个字符串列表、而后结束的Observeable。然后咱们会经过这个字符串列表来填充颜色列表,这里要使用到Observable.just()方法。由这个方法建立的Observable对象的特色是:全部Observer一旦订阅这个Observable就会当即调用onNext()方法并传入Observable.just()的参数,然后由于Observable没有数据能够发送了,onComplete()方法会被调用。ide

Observable<List<String>> listObservable = Observable.just(getColorList());

注意这里的getColorList()是一个不耗时的方法。虽然如今看来这个方法无足轻重,但一会咱们会回到这个方法。学习

下一步,咱们写一个Observer来观察Observable。

listObservable.subscribe(new Observer<List<String>>() { 

    @Override 
    public void onCompleted() { } 

    @Override 
    public void onError(Throwable e) { } 

    @Override
    public void onNext(List<String> colors) {
        mSimpleStringAdapter.setStrings(colors);
    }
});

然后神奇的事情就发生了。如我刚才所说,一旦经过subscribe()方法订阅Observable,就会发生一系列事情:

  1. onNext()方法被调用,被发送的颜色列表会做为参数传入。
  2. 既然再也不有数据能够发送(咱们在Observable.just()中只让Observable发送一个数据),onComplete()方法会被调用。

请记住:经过Observable被订阅后的行为来区分它们

在这个例子中咱们不关心Observable什么时候完成数据的传输,因此咱们不用在onComplete()方法里写代码。并且在这里不会有异常抛出,因此咱们也不用管onError()方法。

写了这么多你可能以为不少余,毕竟咱们本能够在adapter中直接设置做为数据源的颜色列表。请带着这个疑问,和我看下面这个更有趣一些的例子。

案例2:异步加载

在这里咱们要写一个显示电视剧列表的Activity。在Android中RxJava的主要用途就在于异步数据加载。首先让咱们写一个Observable:

Observable<List<String>> tvShowObservable = Observable.fromCallable(new Callable<List<String>>() { 

    @Override 
    public List<String> call() { 
        return mRestClient.getFavoriteTvShows(); 
    }
});

在刚才的例子中,咱们使用Observable.just()来建立Observable,你可能认为在这里能够经过Observable.just(mRestClient.getFavoriteTvShows())来建立Observable。

但在这里咱们不能这么作,由于mRestClient.getFavoriteTvShows()会发起网络请求。若是在这里咱们使用Observable.just(),mRestClient.getFavoriteTvShows()会被当即执行并阻塞UI线程。

使用Observable.fromCallable()方法有两点好处:

  1. 获取要发送的数据的代码只会在有Observer订阅以后执行。
  2. 获取数据的代码能够在子线程中执行。

这两点好处有时可能很是重要。如今让咱们订阅这个Observable。

mTvShowSubscription = tvShowObservable
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<List<String>>() {

        @Override 
        public void onCompleted() { }

        @Override 
        public void onError(Throwable e) { }

        @Override 
        public void onNext(List<String> tvShows){
            displayTvShows(tvShows);
        }
    });

让咱们一个方法一个方法地来看这段代码。subscribeOn会修改咱们刚刚建立的Observable。在默认状况下Observable的全部代码,包括刚才说到的只有在被订阅以后才会执行的代码,都会在执行subscribe()方法的线程中运行。而经过subscribeOn()方法,这些代码能够在其余线程中执行。但具体是哪一个线程呢?

在这个例子中咱们让代码在"IO Scheduler"中执行(Schedulers.io())。如今咱们能够只把Scheduler当作一个能够工做的子线程,这个描述对于如今的咱们已经足够了,不过这其中还有更深层次的内容。

不过咱们的确遇到了一个小障碍。既然Observable会在IO Scheduler中运行,那么它与Observer的链接也会在IO Scheduler中完成。这就意味着Observer的onNext()方法也会在IO Scheduler中运行,而onNext()方法会操做UI中的View,但View只能在UI主线程中操做。

事实上解决这个问题也很简单,咱们能够告诉RxJava咱们要在UI线程中观察这个Observable,也就是,咱们想让onNext()方法在UI线程中执行。这一点咱们能够经过在observeOn()方法中指定另外一个Scheduler来完成,在这里也就是AndroidSchedules.mainThread()所返回的Scheduler(UI线程的Scheduler)。

然后咱们调用subscribe()方法。这个方法最重要,由于Callable只会在有Observer订阅后运行。还记得刚才我说Observable经过其被订阅后的行为来区分吗?这就是一个很好的例子。

还有最后一件事。这个mTvShowSubscription究竟是什么?每当Observer订阅Observable时就会生成一个Subscription对象。一个Subscription表明了一个Observer与Observable之间的链接。有时咱们须要操做这个链接,这里拿在Activity的onDestroy()方法中的代码举个例子:

if (mTvShowSubscription != null && !mTvShowSubscription.isUnsubscribed()) {
    mTvShowSubscription.unsubscribe();
}

若是你与多线程打过交道,你确定会意识到一个大坑:当Activity执行onDestroy()后线程才结束(甚至永不结束)的话,就有可能发生内存泄漏与NullPointerException空指针异常。

Subscription就能够解决这个问题,咱们能够经过调用unsubscribe()方法告诉Observable它所发送的数据再也不被Observer所接收。在调用unsubscribe()方法后,咱们建立的Observer就再也不会收到数据了,同时也就解决了刚才说的问题。

说到这里难点已通过去,让咱们来总结一下:

  • Observable.fromCallable()方法能够拖延Observable获取数据的操做,这一点在数据须要在其余线程获取时尤为重要。
  • subscribeOn()让咱们在指定线程中运行获取数据的代码,只要不是UI线程就行。
  • observeOn()让咱们在合适的线程中接收Observable发送的数据,在这里是UI主线程。
  • 记住要让Observer取消订阅以避免Observable异步加载数据时发生意外。

案例3:使用Single

此次咱们仍是写一个展现电视剧列表的Activity,但此次咱们走一种更简单的风格。Observable挺好用的,但在某些状况下过于重量级。好比说,你可能一经发如今过去的两个方法中咱们只是让Observable发送一个数据,并且咱们历来也没写过onComplete()回调方法。

其实呢,Observable还有一个精简版,叫作Single。Single几乎和Observable如出一辙,但其回调方法不是onComplete()/onNext()/onError(),而是onSuccess()/onError()。

咱们如今把刚才写过的Observable用Single重写一遍。首先咱们要建立一个Single:

Single<List<String>> tvShowSingle = Single.fromCallable(new Callable<List<String>>() { 
    @Override
    public List<String> call() throws Exception {
        mRestClient.getFavoriteTvShows(); 
    }
});

而后订阅一下:

mTvShowSubscription = tvShowSingle
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new SingleSubscriber<List<String>>() {

        @Override 
        public void onSuccess(List<String> tvShows) {
            displayTvShows(tvShows); 
        }

        @Override 
        public void onError(Throwable error) {
            displayErrorMessage(); 
        } 
    });

这段代码和刚才很像,咱们调用subscribeOn()方法以确保getFavoriteTvShows()在子线程中执行。然后咱们调用observeOn()以确保Single的数据被发送到UI线程。

但此次咱们再也不使用Observer,而是使用一个叫SingleSubscriber的类。这个类和Observer很是像,只不过它只有上述两个方法:onSuccess()和onError()。SingleSubscriber之于Single就如Observer之于Observable。

订阅一个Single的同时也会自动建立一个Subscription对象。这里的Subscription和案例2中没有区别,必定要在onDestroy()中解除订阅。

最后一点:在这里咱们添加了处理异常的代码,因此若是mRestClient出了问题,onError()就会被调用。建议你亲手写一个案例玩一玩,体验一下有异常时程序是怎么运行的。

相关文章
相关标签/搜索