RxJava1.0学习笔记之快速入门

简介


RxJava 在 GitHub的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。同时也是基于观察者模式的一个库。

要使用他首先要添加依赖

compile 'io.reactivex:rxjava:1.0.14'
compile 'io.reactivex:rxandroid:1.0.1'  

类介绍


  • Observable 被观察者
  • Observer 观察者
  • subscribe() 他们链接的桥梁
  • Subscriber,他是Observer的实现类,并将方法进行拓展。

这个关系用代码来表示如图所示:

 //观察者
Observer observer = new Observer() {
    @Override
    public void onCompleted() {
        Log.e("onCompleted: ", "完成");
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onNext(String s) {
        Log.e("onNext: ", s);
    }
};`
//被观察者
Observable observable = Observable.create(new Observable.OnSubscribe() {
    @Override
    public void call(Subscriber subscriber) {
        Log.e("call: ", Thread.currentThread().getName());
        subscriber.onNext("我");
        subscriber.onNext("爱");
        subscriber.onNext("你");
        subscriber.onCompleted();
    }
});

然后桥梁将让他们之间产生链接:

observable.subscribe(observer);

这样一个简单的Rxjava模型就写好了,可以看一下输出结果:

com.example.cosima.rxjavalearn E/onNext:: 我
com.example.cosima.rxjavalearn E/onNext:: 爱
com.example.cosima.rxjavalearn E/onNext:: 你
com.example.cosima.rxjavalearn E/onCompleted:: 完成

我们也可以将上面的Observer用Subscriber来代替,如下:

Subscriber subscriber = new Subscriber() {
    @Override
    public void onStart() {
    Log.e("onStart: ", "开始");
    Log.e("onStart: ", Thread.currentThread().getName());
    }

    @Override
    public void onCompleted() {
    Log.e("onCompleted: ", "完成");
    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onNext(String s) {
    Log.e("onNext: ", s);
    }
};

Subscriber中比Observer多了一个Onstart方法,它会在 subscribe 刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。

Observable的创建


上面介绍了一种创建方式是使用create()方法创建的,该方法是最基本的创造事件队列的方法,基于这个方法外,RxJava还提供了一些方法来快捷穿件事件队列

  1. just(T..); 将需要的参数依次传入。
  2. from(T[]); 将需要的参数添加到数组中传入。

将观察者与被观察者联系起来除了subscribe(Observer) 和 subscribe(Subscriber) ,subscribe() 还支持不完整定义的回调。如下所示:

Action1 onNextAction = new Action1() {
    // onNext()
    @Override
    public void call(String s) {
        Log.d(tag, s);
    }
};
Action1 onErrorAction = new Action1() {
    // onError()
    @Override
    public void call(Throwable throwable) {
    // Error handling
    }
};
Action0 onCompletedAction = new Action0() {
    // onCompleted()
    @Override
    public void call() {
        Log.d(tag, "completed");
    }
};

observable.subscribe(onNextAction);
observable.subscribe(onNextAction, onErrorAction);
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);

上述代码提到了Action0和Action1,他们都是RxJava的接口,同样都只有一个方法Call(),不同的是,Action0的Call()方法中是没有参数也没有返回值的,对应了OnCompleted()这个方法;Action1的Call( T param)方法中含有参数,分别对应了OnNext(T param)和OnError(Throwable error)两个方法。具体使用如下:

String[] loves = {"I", "will", "always", "love", "you"};
Observable.from(loves).subscribe(new Action1() {
        @Override
        public void call(String s) {
            Log.e("call: ", s);
        }
    });

最开始的时候就讲了RxJava是可以进行异步操作的,但是上面讲的都是进行的同步操作,下面就讲RxJava的另一个概念Scheduler

线程控制Scheduler


在不指定线程的情况下,RxJava遵循线程不变的原则,在哪个线程调用subscribe(),事件就在哪个线程发生,也在这个线程消费,当我们需要切换线程的时候就需要用到Scheduler。

  • Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
  • 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。
  • 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。

然后我们可以使用subscribeOn() 和 observeOn() 两个方法来对线程进行控制。

  • subscribeOn(): 指定 subscribe() 所发生的线程。事件产生的线程。

  • observeOn(): 指定 Subscriber 所运行在的线程。事件消费的线程。
    然后我们通过代码理解一下这个Scheduler

      Observable.create(new Observable.OnSubscribe() {
          @Override
          public void call(Subscriber subscriber) {
              subscriber.onNext("我");
              subscriber.onNext("爱");
              subscriber.onNext("你");
              subscriber.onCompleted();
          }
      })
              .subscribeOn(Schedulers.io())
              .doOnSubscribe(new Action0() {
                  @Override
                  public void call() {
                      Log.e("call: ", Thread.currentThread().getName());
                      mProgressBar.setVisibility(View.VISIBLE);
                  }
              })
    
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(subscriber);
    

subscribeOn(Schedulers.io()) 指定创建的时间在IO线程中发出,observeOn(AndroidScheculers.mainThread()) 指定事件消费在主线程中消费,这种方式非常常见,适用于子线程取数据,然后主线程显示。同时,可以看到我在上述代码中新添加了一个方法doOnSubscribe(),该方法与Subscriber的OnStart()方法相似,在事件产生前在OnStart()之后就会执行,但是在该方法之前的subscribeOn()不会影响他,只有在他之后且离他最近的一个subscribeOn() 才会影响。

  • observeOn()可以执行多次,他所影响的是指定之后的操作所在的线程。
  • subscribeOn()也可以执行多次,从事件开端就造成影响,有多个的时候只有第一个 subscribeOn() 起作用。

接下来可以说是RxJava最牛逼的地方了。

变换


1. map();

2. flatMap();

让我们首先来看map()

 Observable.from(number)
           .map(new Func1() {
               @Override
               public Integer call(String s) {
                   Integer integer = Integer.valueOf(s);
                   Log.e("call--1--: ", integer + "");
                   return integer;
               }
           })
           .subscribe(new Action1() {
               @Override
               public void call(Integer integer) {
                   Log.e("call--2--: ", integer + "");
               }
           });

在这里又新出现了一个类Func1,他与Action1非常相似,也是RxJava的一个接口,但是与Action1不同的是Func1是有返回值的。可以看到的是在map()中将String类型的参数转换为Integer类型后返回 。

接下来让我们看flatMap(), 这边举个例子,我们要打印学生的课程信息,学生的课程不一定是只有一个的,可能有很多个,所以要这个时候就要用到flatMap();

Student[] students = ...;
Subscriber subscriber = new Subscriber() {
    @Override
    public void onNext(Course course) {
        Log.d(tag, course.getName());
    }
};
Observable.from(students)
        .flatMap(new Func1>() {
            @Override
            public Observable call(Student student) {
                return Observable.from(student.getCourses());
        }   
})
.subscribe(subscriber);

从上面的代码可以看出,flatMap和Map的相同点就是把一个对象转化为另一个对象返回,但是不同的是flatMap()返回的是个Observable对象,并且这个对象并不是直接发送到了回调方法中,而是把这个对象激活,之后将他发送到回调方法中。

变换的原理


这些变换虽然功能各有不同,但实质上都是针对事件序列的处理和再发送。而在 RxJava 的内部,它们是基于同一个基础的变换方法: lift(Operator)。

注意:这不是 lift() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。

public  Observable lift(Operator operator) {
    return Observable.create(new OnSubscribe() {
        @Override
        public void call(Subscriber subscriber) {
            Subscriber newSubscriber = operator.call(subscriber);
            newSubscriber.onStart();
            onSubscribe.call(newSubscriber);
        }
    });
}

在这里我就说一下我所理解的lift()的原理吧:
说简单点就是,你自己定义的Observable1含有lift()时,会生成一个Observable,我们叫他Observable2,Observable2中会有一个OnSubscribe(),然后调用lift()时,新生成的 OnSubscribe 利用 operator.call(subscriber) 生成了一个新的 Subscriber( call() 方法将新 Subscriber 和原始 Subscriber 进行关联)然后通过新生成的Subscriber与Observable1进行订阅有点像一种代理机制,通过事件拦截和处理实现事件序列的变换。

compose: 对 Observable 整体的变换

这个地方就像是对Observable进行封装,实现Observable.Transformer接口并重写Call()就可以了,在这里就不多说了。

RxJava的使用场景和使用方式#

与Retrofit结合使用

直接上代码吧,

1. 首先初始化Retrofit

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://japi.juhe.cn/joke/content/")
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//基于RxJava1.0
            .build();

2. 定义返回Observable的请求

    @GET("text.from?page=1&pagesize=20&key=f1bdc177567c6fbe53d918041004c0b1")
    Observable  getJokeContent();

3. 开始请求并返回数据

    JokeService service = retrofit.create(JokeService.class);
        service.getJokeContent()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1() {
                    @Override
                    public void call(JokeBean jokeBean) {
                        String content = jokeBean.getResult().getData().get(0).getContent();
                        mTextView.setText(content);
                    }
                });

如果需要耗时操作就doOnNext()方法中进行操作,如果需要连续访问的话就使用flatMap(),如下所示

@GET("/token")
public Observable getToken();

@GET("/user")
public Observable getUser(@Query("token") String token, @Query("userId") String userId);

...

getToken()
.flatMap(new Func1>() {
    @Override
    public Observable onNext(String token) {
        return getUser(token, userId);
    })
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
    @Override
    public void onNext(User user) {
        userView.setUser(user);
    }

    @Override
    public void onCompleted() {
    }

    @Override
    public void onError(Throwable error) {
        // Error handling
        ...
    }
});

参考:给Android开发者的RxJava详解
不对之处欢迎指正!推荐一个Android实习&&经验交流群:541144061

你可能感兴趣的:(RxJava1.0学习笔记之快速入门)