RXJava1 简单使用

版权声明:转载请标明出处 https://blog.csdn.net/panyongjie2577 https://blog.csdn.net/panyongjie2577/article/details/89333690

前言

RXJava是基于观察者模式开发的一个开源库,这里的观察者模式与生活中正常的观察者模式是相反的, 生活中的观察者模式是 观察者主动观察被观察者,在被观察者发生变化的时候进行相应处理,例如老师与学生。计算机编程中观察者模式,是需要被观察者主动来报告自定的状态的,在被观察者发生了变化的时候主动通知观察者。这里就出现了订阅和通知与解除订阅三种动作。
在这里插入图片描述

实现观察者模式需要以下几步:

  • 1 创建一个被观察对象Observable
  • 2 被观察者主动订阅观察者subscribe
  • 3 在被观察者发生变化的时候,通知观察者进行处理 doOnNext
  • 4 不使用观察者模式的时候,被观察者解除与观察者之间的订阅关系。

关于RxJava的说明及更多使用请查看下面两个博客,本篇只进行常用的使用说明。
给 Android 开发者的 RxJava 详解
https://gank.io/post/560e15be2dca930e00da1083

RxJava2.0——从放弃到入门
https://www.jianshu.com/p/cd3557b1a474

环境配置

在项目的app下的build.gradle文件中添加如下配置, 这里因为后面需要演示如何与Retrofit2配合使用,所以也添加了Retrofit2的配置

//RxJava
implementation 'io.reactivex:rxjava:1.1.6'
implementation 'io.reactivex:rxandroid:1.2.0'
//Retrofit  2.0.0-beta2
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.okhttp:okhttp:2.5.0'
implementation 'com.squareup.okio:okio:1.6.0'
implementation 'com.google.code.gson:gson:2.4'
implementation 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
implementation "com.squareup.retrofit2:adapter-rxjava:2.1.0"

Observable

简单的订阅与观察

String[] args = {"a", "b", "c"};

//简单示例,在IO线程上实现订阅和观察
Observable.from(args)
   .subscribeOn(Schedulers.io())   //指定在哪个线程上实现订阅
   .observeOn(Schedulers.io())     //指定在哪个线程上实现观察
   .doOnNext(new Action1<String>() {
       @Override
       public void call(String s) {
           //因为观察指定在IO线程,所以这里如果进行UI操作,将会引发异常
           Log.i("RxDemo", s);
       }
   }).subscribe();

运行程序,输出如下:

I/RxDemo: a
I/RxDemo: b
I/RxDemo: c

这里我们需要注意的是,因为我们在代码里指定了订阅行为发生在IO线程上进行,也就是说被观察者执行的操作是在IO线程上的观察者被指定了通知接收行为发生在IO线程, 被观察者发送的通知回调是在io线程上的,这里是不能在通知函数doOnNext中进行UI操作的,否则会引发异常的。

线程间切换

Observable.from(args)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())//在UI线程上进行观察
    .doOnNext(new Action1<String>() {
        @Override
        public void call(String s) {
            //如果需要进行UI操作,观察者需要切换到UI线程上进行观察
            Toast.makeText(getBaseContext(), s, 
		               Toast.LENGTH_SHORT).show();
        }
    }).subscribe();

这里我们在代码里指定了订阅行为发生在主线程上进行,也就是说被观察者执行的操作是在主线程上的,观察者被指定了通知接收行为发生在主线程, 被观察者发送的通知回调是在主线程上的,所以这里可以在通知函数doOnNext中进行UI操作的,不会引发异常的。

完整生命周期

Observable.from(args)
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .doOnNext(new Action1<String>() {
      @Override
      public void call(String s) {
          Log.i(TAG, s);
      }
  })
  .doOnSubscribe(new Action0() {
      @Override
      public void call() {
          Log.i(TAG, "doOnSubscribe-->开始加载");
      }
  })
  .doOnTerminate(new Action0() {
      @Override
      public void call() {
  
          Log.i(TAG, "onTerminate-->加载完成");
      }
  })
  .doOnCompleted(new Action0() {
      @Override
      public void call() {
          Log.i(TAG, "onCompleted-->结束加载");
      }
  })
  .doOnError(new Action1<Throwable>() {
      @Override
      public void call(Throwable throwable) {
          Log.i(TAG, "发生异常了,异常错误是: " + 
              throwable.getMessage());
      }
  })
  .doAfterTerminate(new Action0() {
     @Override
      public void call() {
          Log.i(TAG, "doAfterTerminate-->流程走完了");
      }
  })
  .subscribe();

整个观察者周期一共会调用以下的函数

  • doOnSubscribe 在订阅创建完成以后就会被调用
  • doOnNext在Obserable调用onNext之后进行调用
  • doOnTerminate在Obserable调用onCompleted之前进行调用。
  • doOnCompleted 在Obserable调用onCompleted之后调用
  • doOnError在Obserable调用onError之后调用,流程被中断。
  • doAfterTerminate在Obserable调用onCompleted之后进行调用。

这里onErroronCompleted是互斥的,同一个流程中,只有一个会被调用。

运行程序,日志输入如下:

I/RxDemo: doOnSubscribe-->开始加载
I/RxDemo: a
I/RxDemo: b
I/RxDemo: c
I/RxDemo: onTerminate-->加载完成
I/RxDemo: onCompleted-->结束加载
I/RxDemo: doAfterTerminate-->流程走完了

异常处理

Observable.from(args)
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .doOnSubscribe(new Action0() {
      @Override
      public void call() {
          Log.i(TAG, "doOnSubscribe");
      }
  })
  .doOnTerminate(new Action0() {
      @Override
      public void call() {
          Log.i(TAG, "doOnTerminate 在OnError之前调用");
      }
  })
  .doAfterTerminate(new Action0() {
      @Override
      public void call() {
          Log.i(TAG, "doAfterTerminate 在OnError之后调用");
      }
  })
  .subscribe(new Action1<String>() {
      @Override
      public void call(String s) {
          Log.i("RxDemo", s);
          int a = 1 / 0;
      }
  }, new Action1<Throwable>() {
      @Override
      public void call(Throwable throwable) {
          Log.i(TAG, "发生异常了,异常错误是: " + 
              throwable.getMessage());
      }
  }, new Action0() {
      @Override
      public void call() {
          Log.i(TAG, "onComplete");
      }
  });

运行程序,日志输入如下:

I/RxDemo: doOnSubscribe
I/RxDemo: a
I/RxDemo: 发生异常了,异常错误是: divide by zero

上面这个示例表明,如果在doOnNext中发生了异常,则会出现doOnError,因为业务被中断了,所以不会调用doOnTerminatedoOnCompleteddoAfterTerminate

Observable管理

RxJava提供了CompositeSubscription对Observable进行管理,例如:

  • compositeSubscription.add(observable)的方式对Observable进行管理。
  • compositeSubscription.clear()清空并停止所有正在执行的Observable

简单示例

//对Observable进行管理
private CompositeSubscription compositeSubscription = new CompositeSubscription();

compositeSubscription.add(
	Observable.interval(0, 1000, TimeUnit.MILLISECONDS)
	.subscribeOn(Schedulers.io())
	.observeOn(Schedulers.io())
	.subscribe(time -> {
			if(null == mActivity){
				KLog.i("mActivity is null");
				compositeSubscription.clear();
			}else{
				KLog.i("mActivity is not null");
			}
		}, throwable ->
		     KLog.i("occour exception, " + 
		       throwable.getMessage())
	)
);

RXJava与Retrofit结合使用

Retrofit是一个注解式的网络请求框架,自身与OKHttp结合能够轻便快捷的实现多种网络请求。与RXJava结合使用后更是如虎添翼,轻松实现网络请求的网络切换与链式编程。

定义Retrofit接口类

import retrofit2.http.GET;
import retrofit2.http.Query;
import rx.Observable;

public interface PoetryTestAPI {
    @GET("/getSongPoetry")
    Observable<PoetryList> getPoetryList(@Query("page") int page, @Query("count") int count);
}

初始化Retrofit类

/*这里统一使用retrofit2,所以配置中需要同已修改为retrofit2的配置,
包含retrofit, convert-gson、adapter-rxjava, 具体配置请查看签名的`环境配置`
*/
Retrofit retrofit = new Retrofit.Builder()
       .baseUrl("https://api.apiopen.top")
       //添加Gson转换适配器
       .addConverterFactory(GsonConverterFactory.create())   
       //添加RxJava适配器
       .addCallAdapterFactory(
           RxJavaCallAdapterFactory.create()) 
       .build();
       
PoetryTestAPI poetryTestAPI = 
	retrofit.create(PoetryTestAPI.class);

简单的网络请求

poetryTestAPI.getPoetryList(1, 10)
   .subscribeOn(Schedulers.io())
   .observeOn(AndroidSchedulers.mainThread())
   .doOnSubscribe(() -> {
       Log.i(TAG,"开始加载数据...");
   })
   .doOnTerminate(() ->{
       Log.i(TAG,"数据加载完成,正在解析...");
   })
   .doOnCompleted(() -> {
       Log.i(TAG,"数据加载完毕!!");
   })
   .doAfterTerminate(() -> {
       Log.i(TAG,"数据查询完毕!!");
   })
   .subscribe(new Action1<PoetryList>() {
       @Override
       public void call(PoetryList poetryList) {
           Log.i(TAG,"doOnNext");
           if(null != poetryList) {
               Log.i(TAG, new Gson().toJson(poetryList));
           }
       }
   }, new Action1<Throwable>() {
       @Override
       public void call(Throwable throwable) {
           Log.i(TAG, "发生异常了,异常错误是: " + 
              throwable.getMessage());
       }
   });

运行程序,输入如下:

开始加载数据...
doOnNext
{"code":200,"message":"成功!","result":[{"authors":"宋太祖","content":"欲出未出光辣达,千山万山如火发。|须臾走向天上来,逐却残星赶却月。","title":"日诗"}, ...]}
数据加载完成,正在解析...
数据加载完毕!!
数据查询完毕!!

优化网络请求

定义一个转换器

/*
 * 定义一个转换器,用于实现订阅者和观察者之间的线程切换
 * Observable.Transformer<T, R>
 *   @param <T> the first argument type
 *   @param <R> the result type
 * */
Observable.Transformer<Object, Object> composeTransformer =
     observable -> observable.throttleFirst(
                  500, TimeUnit.MILLISECONDS)
	.subscribeOn(Schedulers.io())
	.observeOn(AndroidSchedulers.mainThread());

使用Lamdba表达式

1 这里如果报错提示你需要使用Lamdba表达式,需要使用jdk1.8, 否则会报错提示
**Lamdba express are not supported at language level ‘7’ **
2 Lamdab表达式格式 ‘(参数列表) -> { 代码块 }’ 或者 ‘参数名 -> { 代码块 }’

poetryTestAPI.getPoetryList(1, 10)
	.compose(composeTransformer)
	.doOnSubscribe(() -> Log.i(TAG, "开始执行数据!!"))
	.doAfterTerminate(() -> Log.i(TAG, "数据查询完毕!!"))
	.subscribe((Object poetryList) -> {
           Log.i(TAG, "doOnNext");
           if (null != poetryList) {
                Log.i(TAG, new Gson().toJson(poetryList));
           }
    },
    (Throwable throwable) ->{
       Log.i(TAG, "发生异常了,异常错误是: " +
               throwable.getMessage());
    }
 );

或者

poetryTestAPI.getPoetryList(1, 10)
   .compose(composeTransformer)
   .doOnSubscribe(() -> Log.i(TAG, "开始加载数据!!"))
   .doAfterTerminate(() -> Log.i(TAG, "加载数据完成!!"))
   .subscribe(list -> {
       Log.i(TAG, "doOnNext");
       if (null != list) {
           Log.i(TAG, new Gson().toJson(list));
       }
   }, throwable -> {
       Log.i(TAG, "发生异常了,异常错误是: " +
            throwable.getMessage());
   });

运行程序,输入如下:

开始加载数据...
doOnNext
{"code":200,"message":"成功!","result":[{"authors":"宋太祖","content":"欲出未出光辣达,千山万山如火发。|须臾走向天上来,逐却残星赶却月。","title":"日诗"}, ...]}
数据查询完毕!!

猜你喜欢

转载自blog.csdn.net/panyongjie2577/article/details/89333690
0条评论
添加一条新回复