Rxjava2.0初探

1. 前言

想必大家对Rxjava或者有所耳闻或者已经深入研究并在开发中使用,总之Rxjava风靡全球。现在得一空闲,我将我理解的Rxjava在这里述说一二,也为自己的使用做个记录,希望大家多多指点。本文主要介绍Rxjava2.0的基本使用和Rxjava结合Retrofit的使用。

2. Rxjava的作用

那么Rxjava能为我们做些什么呢?Rxjava主要有两个作用:①异步②发送接收数据。而这两个作用其实已经有很成熟的框架了,为什么还要使用Rxjava呢?Rxjava的优势在于采用了观察者模式结合了响应式编程,还有非常强大的操作符及调度器来控制流程,这样就使得代码风格简洁,而且可维护性强。理论比较抽象,且慢慢看下去。

3.Rxjava中的基本概念

Rxjava2.0中有很多新的API,我们先看下最常用的概念:

Observable:“可观察的”,被观察者,事件的产生者,整个事件的起点
Observer:“观察”,观察者,事件的处理者
SubjectSubject既可以充当观察者,也可以充当被观察者
Subscriber:同样也是观察者
subscribe():订阅,被观察者通过subscribe( )响应到观察者那里去

以上是接触Rxjava1.0和2.0需要了解的最基础的概念,Rxjava1.0和2.0还有一些区别的概念:

Rxjava 1.0:
Action0:RxJava中的一个接口,它只有一个无参call()方法,且无返回值,同样还有Action1,Action2…Action9等,Action1封装了含有 1 个参的call()方法,即call(T t),Action2封装了含有 2 个参数的call方法,即call(T1 t1,T2 t2)
Func0:与Action0非常相似,也有call()方法,但是它是有返回值的,同样也有Func0、Func1…Func9;
Rxjava 2.0 
Flowable:能够支持背压的Observable
Disposable:代替了Rxjava 1.0 的Subscription,可以取消观察者接收数据
Action1被重命名为Consumer;Action2 被重命名为BiConsumer;ActionN 被Consumer<Object[]> 代替。

概念只要有个印象就行,下面会详细介绍的。接下来是Rxjava的基本的流程:由Observable发出事件,每发出一个事件,就会调用它的Subscriber的onNext方法,发生错误时,会调用Subscriber的onError方法,事件结束时会调用Subscriber的onCompleted方法。光说概念是不好理解的,下面我们看下Rxjava的最基本的使用方法。

4. Rxjava2.0的基本使用

4.1 Rxjava配置

在app的build.gradle下添加依赖:

    compile 'io.reactivex.rxjava2:rxjava:2.0.1'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

其中添加rxandroid,是使用与android开发的,像之后的线程调度器的api(切换到主线程)就源自rxandroid

4.2 Observable/Observer的创建

Observable的create()方法创建

Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> e) throws Exception {
        Log.d(TAG, "subscribe: emit_1");
        e.onNext("事件1");
        Log.d(TAG, "subscribe: emit_2");
        e.onNext("事件2");
        Log.d(TAG, "subscribe: emit_3");
        e.onNext("事件3");
        Log.d(TAG, "subscribe: emit_onComplete");
        e.onComplete();
        Log.d(TAG, "subscribe: emit_4");
        e.onNext("事件4");
    }
});

Observer的创建:

Observer<String> observer =new Observer<String>() {
    @Override
    public void onSubscribe(Disposable d) {
        Log.d(TAG, "onSubscribe: ");
    }

    @Override
    public void onNext(String value) {
        Log.d(TAG, "onNext: 接收"+value);
    }

    @Override
    public void onError(Throwable e) {
        Log.d(TAG, "onError: "+e.toString());
    }

    @Override
    public void onComplete() {
        Log.d(TAG, "onComplete: ");
    }
};

有了观察者和被观察者,就差一个订阅的方法:

observable.subscribe(observer);

运行一下结果:

D/MAIN: onSubscribe: 
D/MAIN: subscribe: emit_1
D/MAIN: onNext: 接收事件1
D/MAIN: subscribe: emit_2
D/MAIN: onNext: 接收事件2
D/MAIN: subscribe: emit_3
D/MAIN: onNext: 接收事件3
D/MAIN: subscribe: emit_onComplete
D/MAIN: onComplete: 
D/MAIN: subscribe: emit_4

首先先看下ObservableEmitter和Disposable的含义:
ObservableEmitter:Emitter是发射器的意思,在这里也就是发送事件,可以发送onNext(T value)、onComplete()和onError(Throwable error)事件。根据ObservableEmitter发射的事件Observer观察者分别在onNext(T value)、onComplete()和onError(Throwable error)接收事件。事件是依次发送的,需要注意的是这里有一定的规则
①当ObservableEmitter发送了onComplete(),之后发送的事件,Observer不再接收
②ObservableEmitter可以不主动发送onError事件,程序运行发生异常时,Observer也会接收到onError事件,只要Observer接收到onError事件,就不会再接收其他事件,但ObservableEmitter不能发送多个onError事件,当发送第二个是,程序会崩溃。
了解了ObservableEmitter,下面看下Disposable:用完即可丢弃的。简单理解就是,当Disposable执行dispose()方法后,ObservableEmitter依然发送数据,但是Observer不再处理数据。
更改Observer的创建:

Observer<String> observer =new Observer<String>() {
           private Disposable mDisposable;
           @Override
           public void onSubscribe(Disposable d) {
               Log.d(TAG, "onSubscribe: ");
               mDisposable = d;
           }

           @Override
           public void onNext(String value) {
               Log.d(TAG, "onNext: 接收"+value);
               if (value.equals("事件1")){
                   Log.d(TAG, "dispose");
                   mDisposable.dispose();
                   Log.d(TAG, "isDisposed : " + mDisposable.isDisposed());
               }
           }

           @Override
           public void onError(Throwable e) {
               Log.d(TAG, "onError: "+e.toString());
           }

           @Override
           public void onComplete() {
               Log.d(TAG, "onComplete: ");
           }
       };
observable.subscribe(observer);

看下运行的结果:

D/MAIN: onSubscribe: 
D/MAIN: subscribe: emit_1
D/MAIN: onNext: 接收事件1
D/MAIN: dispose
D/MAIN: isDisposed : true
D/MAIN: subscribe: emit_2
D/MAIN: subscribe: emit_3
D/MAIN: subscribe: emit_onComplete
D/MAIN: subscribe: emit_4

注意的一点:onSubscribe(Disposable d) 首先执行
这里可以看到:在接收到事件1后执行了mDisposable.dispose();,之后的事件就被抛弃了,不再执行
另外, subscribe()有多个重载的方法:

public final Disposable subscribe() {}
public final Disposable subscribe(Consumer<? super T> onNext) {}
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {} 
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) {}
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) {}
public final void subscribe(Observer<? super T> observer) {}

其中,不带参数的subscribe(),就是不处理事件,实际使用的较少
带有一个Consumer参数的subscribe(),表示只关心onNext事件,这里使用了链式结构:

Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> e) throws Exception {
        Log.d(TAG, "subscribe: emit_1");
        e.onNext("事件1");
        Log.d(TAG, "subscribe: emit_2");
        e.onNext("事件2");
        Log.d(TAG, "subscribe: emit_3");
        e.onNext("事件3");
        Log.d(TAG, "subscribe: emit_onComplete");
        e.onComplete();
        Log.d(TAG, "subscribe: emit_4");
        e.onNext("事件4");
    }
}).subscribe(new Consumer<String>() {

    @Override
    public void accept(String s) throws Exception {
        Log.d(TAG, "accept: "+s);
    }
});

运行结果:

D/MAIN: subscribe: emit_1
D/MAIN: accept: 事件1
D/MAIN: subscribe: emit_2
D/MAIN: accept: 事件2
D/MAIN: subscribe: emit_3
D/MAIN: accept: 事件3
D/MAIN: subscribe: emit_onComplete
D/MAIN: subscribe: emit_4

可以看出onComplete依然起效果,但是Consumer只关心发送的onNext事件。

4.3 Rxjava利用操作符

上面虽然成功创建了Observable和Observer,但是略显麻烦,RxJava其实提供了很多便捷的方法来帮助我们减少代码,这里先介绍常见的创建Observable的操作符

4.3.1 just创建Observable

适用场景:创建一个Observable并自动为你调用onNext( )发射数据:

Observable.just("事件1","事件2","事件3","事件4").subscribe(new Consumer<String>() {
    @Override
    public void accept(String s) throws Exception {
        Log.d(TAG, "accept: "+s);
    }
});
4.3.2 interval创建Observable

适用场景:创建一个按固定时间间隔发射整数序列的Observable,可以用于定时操作

//每隔1秒发一次秒数
Observable.interval(1, TimeUnit.SECONDS).subscribe(new Consumer<Long>() {
    @Override
    public void accept(Long aLong) throws Exception {
        Log.d(TAG, "accept: "+aLong);
    }
});
4.3.3 range创建Observable

适用场景:创建一个发射特定整数序列的Observable,第一个参数为起始值,第二个为发送的个数,如果为0则不发送,负数则抛异常

Observable.range(10, 5).subscribe(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) throws Exception {
        Log.d(TAG, "accept: "+integer);
    }
});
4.3.4 repeat创建Observable

适用场景:创建一个重复发射特定数据的Observable

Observable.just("repeat").repeat(3).subscribe(new Consumer<String>() {
    @Override
    public void accept(String s) throws Exception {
        Log.d(TAG, "accept: "+s);
    }
});
4.3.5 defer创建Observable

适用场景:直到有观察者订阅时才创建Observable,而且这个Observable是使用Observable工厂方法生成一个新的Observable。
下面与just方法创建做一个对比:

num = 1;
Observable<Integer> defer = Observable.defer(new Callable<ObservableSource<Integer>>() {
    @Override
    public ObservableSource<Integer> call() throws Exception {
        return Observable.just(num);
    }
});
num = 2;
defer.subscribe(new Consumer<Integer>() {
    @Override
    public void accept(Integer Integer) throws Exception {
        Log.d(TAG, "accept:defer:num=" + Integer);
    }
});
num = 1;
Observable<Integer> just = Observable.just(num);
num = 2;
just.subscribe(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) throws Exception {
        Log.d(TAG, "accept:just:num=" + integer);
    }
});

运行结果:

D/HANDLERACTIVITY: accept:defer:num=2
D/HANDLERACTIVITY: accept:just:num=1

像这样操作符,还有很多,一下子说这么多,也记住住,在以后的使用中会陆续介绍

5. 线程调度Schedulers

Rxjava最大的优势就是强大的操作符和便捷的线程调度,操作符需要慢慢学习,下面看下Rxjava如何实现线程调度的:先看下被观察者发送数据和观察者接收数据都在哪个线程

Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> e) throws Exception {
        Log.d(TAG, "Observable thread : " + Thread.currentThread().getName());
        Log.d(TAG, "subscribe: emit_1");
        e.onNext("事件1");
    }
}).subscribe(new Consumer<String>() {
    @Override
    public void accept(String s) throws Exception {
        Log.d(TAG, "Observer thread :" + Thread.currentThread().getName());
        Log.d(TAG, "onNext: " + s);
    }
});

看下运行结果:

D/THREAD: Observable thread : main
D/THREAD: subscribe: emit_1
D/THREAD: Observer thread :main
D/THREAD: onNext: 事件1

可以看出:发送和接收数据默认是在主线程的。实际上我们开发的时候,经常要把耗时操作放到子线程中执行,这个时候Rxjava线程调度器Schedulers就可以大展身手了,先看代码:

Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> e) throws Exception {
        Log.d(TAG, "Observable thread : " + Thread.currentThread().getName());
        Log.d(TAG, "subscribe: emit_1");
        e.onNext("事件1");
    }
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
    @Override
    public void accept(String s) throws Exception {
        Log.d(TAG, "Observer thread :" + Thread.currentThread().getName());
        Log.d(TAG, "onNext: " + s);
    }
});

运行结果:

D/THREAD: Observable thread : RxCachedThreadScheduler-1
D/THREAD: subscribe: emit_1
D/THREAD: Observer thread :main
D/THREAD: onNext: 事件1

被观察者发送事件的线程变成了一个子线程,而接收事件的线程还是主线程,关键就在于下面这两句代码:

//指定Observable发送事件的线程
.subscribeOn(Schedulers.io())
//指定Observer接收事件的线程
.observeOn(AndroidSchedulers.mainThread())

那么,Schedulers.io()是什么呢?

Schedulers.newThread():总是启用新线程,并在新线程执行操作。
Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
Schedulers.computation():计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
AndroidSchedulers.mainThread():它指定的操作将在 Android 主线程运行。这个需要增加RxAndroid依赖

运行结果中的CacheThread其实就是IO线程池中的一个
需要注意的是:
①多次调用subscribeOn() 只有第一次的有效, 其余的会被忽略.
②每调用一次observeOn() , Observer接收事件的线程就会切换一次.
比如下面的例子:

Observable.create(new ObservableOnSubscribe<String>() {
    @Override
    public void subscribe(ObservableEmitter<String> e) throws Exception {
        Log.d(TAG, "Observable thread : " + Thread.currentThread().getName());
        e.onNext("事件1");
        e.onNext("事件2");
    }
})
.subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.observeOn(Schedulers.io())
.subscribe(new Consumer<String>() {
    @Override
    public void accept(String s) throws Exception {
        Log.d(TAG, "Observer thread :" + Thread.currentThread().getName());
        Log.d(TAG, "onNext: " + s);
    }
});

运行结果如下

D/THREAD: Observable thread : RxNewThreadScheduler-1
D/THREAD: Observer thread :RxCachedThreadScheduler-2
D/THREAD: onNext: 事件1
D/THREAD: Observer thread :RxCachedThreadScheduler-2
D/THREAD: onNext: 事件2

可以看出,subscribeOn的第二次调度:subscribeOn(Schedulers.io())并没有起作用,observeOn的第一次调度observeOn(AndroidSchedulers.mainThread())也并没有起作用,其实起作用了,但是observeOn又立即调度到Schedulers.io()上了。
开发中我们最常见的使用调度器的地方无非就是网络请求和查询数据库。

5.1 Schedulers应用在网络请求

网络请求框架,这里使用Retrofit,原因很简单Retrofit完美支RxJava。相信大家都用过Retrofit,这里做下简单的封装

5.1.1 添加Retrofit依赖

在app的build.gradle下添加依赖:

//retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'
//Gson converter
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
//okhttp
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
5.1.2 Retrofit和Rxjava简单封装

这里我们请求:http://c.3g.163.com/photo/api/list/0096/4GJ60096.json,网易新闻的一个图片列表
定义Retrofit需要的Api接口

public interface Api {
    //http://c.3g.163.com/photo/api/list/0096/4GJ60096.json

    @Headers(CACHE_CONTROL_NETWORK)
    @GET("photo/api/list/0096/4GJ60096.json")
    Observable<List<PhotoInfo>> getPhotoList();
}

增加了请求头:

 //(假如请求了服务器并在a时刻返回响应结果,则在max-age规定的秒数内,浏览器将不会发送对应的请求到服务器,数据由缓存直接返回)
    static final String CACHE_CONTROL_NETWORK = "Cache-Control: public, max-age=3600";

编写一个Retrofit工具类:RetrofitService,定义一个初始化方法以及添加调度器的方法

public static void init() {
    // 指定缓存路径,缓存大小100Mb
    Cache cache = new Cache(new File(MyApp.getAppContext().getCacheDir(), "HttpCache"),
            1024 * 1024 * 100);
    OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(cache)
            .retryOnConnectionFailure(true)
            //增加一个log拦截器,类似这样的还可以添加网络错误拦截器addNetworkInterceptor()
            .addInterceptor(sLoggingInterceptor)
            .connectTimeout(10, TimeUnit.SECONDS)
            .build();

    Retrofit retrofit = new Retrofit.Builder()
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .baseUrl(HOST)
            .build();
    sService = retrofit.create(Api.class);
}
/**
 * 获取图片列表的方法,线程调度
 * @return
 */
public static Observable<List<PhotoInfo>> getPhotoList() {
    return sService.getPhotoList()
            .subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());
}

自定义MyApp extends Application,获取一个全局的Context以及初始化RetrofitService

public class MyApp extends Application{
    public static Context sContext;
    @Override
    public void onCreate() {
        super.onCreate();
        sContext = this;
        RetrofitService.init();
    }
    public static Context getAppContext(){
        return sContext;
    }
}
5.1.3 使用封装的工具类

在清单文件中添加联网的权限后,Activity中这样使用:

RetrofitService.getPhotoList()
       .subscribe(new Observer<List<PhotoInfo>>() {
           @Override
           public void onSubscribe(Disposable d) {
               if (mCompositeDisposable!=null)
               mCompositeDisposable.add(d);
           }

           @Override
           public void onNext(List<PhotoInfo> value) {
               Toast.makeText(ThreadAvtivity.this, "请求成功", Toast.LENGTH_SHORT).show();
           }

           @Override
           public void onError(Throwable e) {
               Toast.makeText(ThreadAvtivity.this, "请求失败", Toast.LENGTH_SHORT).show();
           }

           @Override
           public void onComplete() {

           }
       });

其中在onSubscribe(Disposable d)方法中将Disposable 添加到CompositeDisposable集合中(CompositeDisposable在Activity的onCreate方法中new出来),这个操作主要是为了防止Activity意外销毁时,利用Disposable停止接收事件

/**
 * Disposable停止接收事件,相当于遍历集合disposable.dispose();
 */
@Override
protected void onDestroy() {
    super.onDestroy();
    if (mCompositeDisposable!=null)
    mCompositeDisposable.clear();
}

5.2 Schedulers应用在查询数据库

这里我们使用GreenDao 3.0 进行数据库的操作。GreenDao 3.0 的操作在这里不是重点,若有不懂的,请查阅http://blog.csdn.net/mr_zhang0101/article/details/73486024

5.2.1 写一个GreenDao需要的实体类

例如一个User的javabean:

@Entity
public class User {
    @Id(autoincrement = true)
    private Long id;
    @Property(nameInDb = "user_name")
    private String name;
    @Property(nameInDb = "tel_phone")
    private String phone;
    @Generated(hash = 666779429)
}
5.2.2 GreenDao添加数据

make module之后,拿到UserDao:

DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(getApplicationContext(),"user.db",null);
mDaoMaster = new DaoMaster(helper.getWritableDatabase());
mDaoSession = mDaoMaster.newSession();
mUserDao = mDaoSession.getUserDao();

由于GreenDao默认建立新表,所以这里提前添加一部分数据:

final List<User> users = Arrays.asList(new User(null,"user_1","001"),
        new User(null,"user_2","002"),
        new User(null,"user_3","003"),
        new User(null,"user_4","004"),
        new User(null,"user_5","005"),
        new User(null,"user_6","006"),
        new User(null,"user_7","007"),
        new User(null,"user_8","008"),
        new User(null,"user_9","009"));
mUserDao.getSession().runInTx(new Runnable() {
    @Override
    public void run() {
        for (int i = 0; i < users.size(); i++) {
            User user = users.get(i);
            mUserDao.insertOrReplace(user);
        }
    }
});
5.2.3 Rxjava线程调度—查询数据库
Observable.create(new ObservableOnSubscribe<List<User>>() {
    @Override
    public void subscribe(ObservableEmitter<List<User>> e) throws Exception {
        List<User> userList = mUserDao.queryBuilder()
                //限定查询的条件
                .where(UserDao.Properties.Id.notEq(10))
                //设置按照排序方式
                .orderAsc(UserDao.Properties.Id)
                //限制查询个数
                .limit(9)
                .build().list();
        e.onNext(userList);
        e.onComplete();
    }
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).
    subscribe(new Observer<List<User>>() {
    @Override
    public void onSubscribe(Disposable d) {
        mCompositeDisposable.add(d);
    }

    @Override
    public void onNext(List<User> value) {
        Log.d(TAG, "onNext: "+value.toString());
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {

    }
});

以上就是Rxjava的初探,下篇着重介绍Rxjava强大的操作符
Demo地址:https://github.com/Mr-zhang0101/Rxjava2.0Test

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值