当前位置:   article > 正文

RxJava 2.0版本使用精炼详解_io.reactivex.rxjava2:rxjava

io.reactivex.rxjava2:rxjava

一,前期基础知识储备

笔者之前写过两篇关于RxJava1.0的文章

RxJava理论讲解和简单实现

RxJava常见操作符讲解》,感兴趣的读者可以看一看。里面有有关RxJava异步操作库的详细介绍,本文不再赘述。

RxJava1.0版本添加依赖:

  1. implementation 'io.reactivex:rxandroid:1.2.1'
  2. implementation 'io.reactivex:rxjava:1.2.1'

RxJava2.0版本添加依赖:

  1. // RxJava2.0
  2. implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
  3. implementation 'io.reactivex.rxjava2:rxjava:2.1.3'

注意二者的依赖环境已经发生改变,所以类和接口所处的包都已经发生改变。

目前RxJava已经更新到2.0版本,2.0版本和1.0版本还是有比较大的区别,这里会在下面的代码中有所体现。

二,上代码,具体实现

1. RxJava2的基础使用

从打印“Hello world”开始,给出从简单到复杂的不同实现方式。

1)简单方式

  1. private static void helloworldSimple() {
  2. // 创建消费者,消费者接收一个String类型的事件
  3. Consumer<String> consumer = new Consumer<String>() {
  4. @Override
  5. public void accept(String s) throws Exception {
  6. Log.d(TAG, "accept: 0," + s);
  7. }
  8. };
  9. Observable.just("Hello WOrld").subscribe(consumer);
  10. }

打印结果:

accept: 0,Hello WOrld

在简单版本中,我们创建了一个消费者consumer,其实也可以称之为订阅者或者观察者,消费者实现accept()方法,接收一个字符串类型的数据或者事件。

被观察者Observable通过just()方法发出一个“Hello World”的呼唤,然后我们使用subscribe方法指定呼唤的接收者或者消费者,即consumer。那么consumer就能接收到被观察者的呼唤,打印出log。

2)复杂方式

  1. /**
  2. * Observer相比Consumer,会对消息的处理更加细化
  3. */
  4. private static void helloworldComplex() {
  5. // 创建一个观察者
  6. Observer<String> observer = new Observer<String>() {
  7. // 当Observable 调用subscribe方法时会回调该方法
  8. // onSubscribe表示已经开始观察被观察者了
  9. @Override
  10. public void onSubscribe(Disposable d) {
  11. Log.d(TAG, "onSubscribe: 1");
  12. }
  13. // 调用onSubscribe方法后
  14. // 表示收到被观察者的消息
  15. @Override
  16. public void onNext(String s) {
  17. Log.d(TAG, "onNext: 2," + s);
  18. }
  19. // 出错时调用
  20. @Override
  21. public void onError(Throwable e) {
  22. }
  23. // onNext之后调用
  24. // 表示接收消息结束
  25. @Override
  26. public void onComplete() {
  27. Log.d(TAG, "onComplete: 3");
  28. }
  29. };
  30. Observable.just("Hello World").subscribe(observer);
  31. }

打印结果为:

  1. onSubscribe: 1
  2. onNext: 2,Hello World
  3. onComplete: 3

这里我们创建了一个Observer而不是一个Consumer,Observer在接口方法上要多很多,有onSubscribe(), onNext(), onError(), onComplete()。被观察者还是Observable,也发出一声“Hello World”,然后通过subscribe指定观察者observer。

从结果中,可以看到observer中方法的调用顺序,onSubscribe()表示已经开始观察被观察者了,onNext()表示收到被观察者的消息,onComplete()表示接收消息结束。所以Observer相比Consumer会对消息的处理更加细化。

3)受控制的复杂方式

  1. /**
  2. * 在onSubscribe方法中会接收到一个Disposable对象,
  3. * 该对象相当于一个开关,如果开关关闭,则观察者不会接收到任何事件或数据
  4. */
  5. private static void helloworldComplexDisposable() {
  6. Observer<String> observer = new Observer<String>() {
  7. // 声明一个Disposable对象
  8. Disposable disposable;
  9. @Override
  10. public void onSubscribe(Disposable d) {
  11. disposable = d; // 保存disposable对象
  12. }
  13. @Override
  14. public void onNext(String s) {
  15. Log.d(TAG, "onNext: 2," + s);
  16. if (s.equals("No")) {
  17. disposable.dispose();
  18. }
  19. }
  20. @Override
  21. public void onError(Throwable e) {
  22. }
  23. @Override
  24. public void onComplete() {
  25. Log.d(TAG, "onComplete: 3");
  26. }
  27. };
  28. Observable.just("Hello World","No","No").subscribe(observer);
  29. }

打印结果如下:

  1. onNext: 2,Hello World
  2. onNext: 2No

在onSubscribe()方法中会接收一个Disposable对象,该对象相当于一个开关,如果开关关闭,则观察者不会收到任何事件和数据。

使用一个变量保存Disposable对象,在onNext方法中如果传过来的字符串为“No”,则调用dispose()方法关闭事件的接收。被观察者会发出3个字符串,执行结果可以看到最后一个字符串没有打印,甚至onComplete()方法都不会执行。

4)十分复杂的方式

  1. /**
  2. * 使用Create方法创建被观察者,并实现subscribe方法,
  3. * 接收一个ObservableEmitter对象,即被观察者的发射器,发射器能够发出数据和事件
  4. * 使用链式调用,让代码看起来更加整洁,
  5. * 上面发出数据和事件,下面接收数据和事件
  6. */
  7. private static void helloworldPlus() {
  8. Observable.create(new ObservableOnSubscribe<String>() {
  9. @Override
  10. public void subscribe(ObservableEmitter<String> emitter) throws Exception {
  11. Log.d(TAG, "subscribe: send hello world");
  12. emitter.onNext("hello world");
  13. Log.d(TAG, "subscribe: send No");
  14. emitter.onNext("No");
  15. Log.d(TAG, "subscribe: send No");
  16. emitter.onNext("No");
  17. Log.d(TAG, "subscribe: send complete");
  18. emitter.onComplete();
  19. }
  20. }).subscribe(new Observer<String>() {
  21. @Override
  22. public void onSubscribe(Disposable d) {
  23. Log.d(TAG, "onSubscribe: ");
  24. }
  25. @Override
  26. public void onNext(String s) {
  27. Log.d(TAG, "onNext: " + s);
  28. }
  29. @Override
  30. public void onError(Throwable e) {
  31. Log.d(TAG, "onError: ");
  32. }
  33. @Override
  34. public void onComplete() {
  35. Log.d(TAG, "onComplete: ");
  36. }
  37. });
  38. }

观察者还是原来的观察者,被观察者则使用create()的方法创建出来,并实现了subscribe()方法,接收一个ObservableEmitter对象,即被观察者的发射器发射器能够发出数据和事件

打印结果为:

  1. onSubscribe:
  2. subscribe: send hello world
  3. onNext: hello world
  4. subscribe: send No
  5. onNext: No
  6. subscribe: send No
  7. onNext: No
  8. subscribe: send complete
  9. onComplete:

从打印结果可知,发射器每发出一个数据或者事件,观察者就会收到。上述代码中使用了链式调用,让代码看起来更加整洁。上面发出数据和事件,下面接收数据和事件。

2.RxJava操作符

RxJava提供了大量的操作符来完成对数据的处理,这些操作符也可以理解为函数。如果把RxJava比作一条数据流水线,那么操作符就是一道工序,数据通过这些工序的加工变换,组装,最后生产出我们需要的数据。

记住:操作符都是对被观察发出数据的操作。

1)过滤操作符filter

2019男篮世界杯,中国最终负于委内瑞拉,其中关键一局中国对战波兰,周琦发球失误,罚球失误,将比赛拖入加时赛,最终输掉比赛,由此由来成语“摇头叹琦”。这里演示过滤“摇头叹琦”。

  1. /**
  2. * filter 过滤操作符
  3. */
  4. private static void filter() {
  5. Observable.just("姚明","阿联","摇头叹琦","大侄子")
  6. .filter(new Predicate<String>() {
  7. @Override
  8. public boolean test(String s) throws Exception {
  9. Log.d(TAG, "test: " + s);
  10. return s.equals("摇头叹琦"); // 只检查出摇头叹琦
  11. }
  12. })
  13. .subscribe(new Consumer<String>() {
  14. @Override
  15. public void accept(String s) throws Exception {
  16. Log.d(TAG, "accept: " + s);
  17. }
  18. });
  19. }

打印结果为:

  1. test: 姚明
  2. test: 阿联
  3. test: 摇头叹琦
  4. accept: 摇头叹琦
  5. test: 大侄子

2)map变换操作符

  1. private static void map () {
  2. Student student = new Student("Jack");
  3. // map操作符,从student类型转换成Developer
  4. Observable.just(student).map(new Function<Student, Developer>() {
  5. @Override
  6. public Developer apply(Student student) throws Exception {
  7. Log.d(TAG, "apply: " + student.toString());
  8. Developer developer = new Developer();
  9. developer.setName(student.getName());
  10. developer.setSkill("Android");
  11. return developer;
  12. }
  13. }).subscribe(new Observer<Developer>() {
  14. @Override
  15. public void onSubscribe(Disposable d) {
  16. Log.d(TAG, "onSubscribe: ");
  17. }
  18. @Override
  19. public void onNext(Developer developer) {
  20. Log.d(TAG, "onNext: " + developer);
  21. }
  22. @Override
  23. public void onError(Throwable e) {
  24. Log.d(TAG, "onError: ");
  25. }
  26. @Override
  27. public void onComplete() {
  28. Log.d(TAG, "onComplete: ");
  29. }
  30. });
  31. }

map操作符能够完成数据类型的转换。被观察者发送出一个student,而观察者想要接收一个developer(两个都是简单的实体类),那么在student发送给观察者之前,需要对student进行一些培训,让它转换成一个developer。

打印结果为:

  1. onSubscribe:
  2. apply: Student{name='Jack'}
  3. onNext: Developer{name='Jack', skill='Android'}
  4. onComplete:

结果:被观察者发送出一个Student,在观察者的onNext()方法中收到了一个Developer。

篇幅有限,文中只介绍了两种操作符的用法,更多内容请参考:

RxJava2-Android-Samples

 

3.异步

作为一个异步操作库,RxJava提供了非常方便的API来完成线程的调度,内置的线程调度器有:

  • Schedule.single(),单线程调度器,线程可复用;
  • Schedule.newThread(),为每个任务创建新的线程;
  • Schedule.io(),处理I/O任务,内部线程池实现,可根据需求增长;
  • Schedule.computation(),处理计算任务,如事件循环和回调任务
  • AndroidSchedulers.mainThread(),Android主线程调度器,属于RxAndroid。

线程调度器实际上指定事件或者数据在什么样的线程中处理。这里主要涉及两个API:subscribeOn()observeOn()

1)subscribeOn

默认情况下,被观察者和观察者在同一线程中执行。而subscribeOn方法实际上是指定被观察者的代码在那种线程中执行。

需要注意的是,subscribeOn方法调用的位置没有特殊指定,它可以放置在其他操作符的前面,中间或者后面,subscribeOn也可以被多次调用,但以第一次调用为准。

2)observerOn

observeOn指定的是后续的操作符以及观察者的代码在什么样的线程中执行。而且observeOn可以被多次调用,每次都生效。

注意observerOn既可以指定被观察者操作符的线程;又可以指定观察者所在的线程

______________________________________________________________________________

4. RxJava2.0与Retrofit2.0集成

笔者之前写过三篇Retrofit的文章

Retrofit基础理论和简单实现

Retrofit各种注解的使用

RxJava+Retrofit完成网络请求

感兴趣的读者可以去看一看,里面详细阐述了Retrofit2.0的用法,并且结合RxJava1.0实现了简单的网络请求。

1)添加依赖并开启网络权限

  1. compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
  2. compile 'io.reactivex.rxjava2:rxjava:2.1.3'
  3. compile 'com.squareup.retrofit2:retrofit:2.3.0'
  4. compile 'com.squareup.retrofit2:converter-gson:2.3.0'
  5. compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
 <uses-permission android:name="android.permission.INTERNET"/>

2)定义网络接口

通过豆瓣API去请求豆瓣电影Top250的网址:

http://douban.uieee.com/v2/movie/top250?start=0&count=10

 

所以定义的接口如下:

  1. public interface Api {
  2. @GET("top250")
  3. Observable<MovieBean> listTop250(@Query("start") int start,
  4. @Query("count") int count);
  5. }

注意:豆瓣API接口网址可能会有变化,以豆瓣API的官方文档为准。

参数start表示查询数据的起始位置,count表示查询数据的个数。返回Observeable类型而不是Call类型。MovieBean为网络结果解析成的JavaBean。

3) 使用单例模式获取Retrofit实例

  1. public class MovieRetrofit {
  2. private static MovieRetrofit sMovieRetrofit;
  3. private final Api mApi;
  4. // 使用单例模式
  5. public static MovieRetrofit getInstance() {
  6. if (sMovieRetrofit == null) {
  7. synchronized (MovieRetrofit.class) {
  8. if (sMovieRetrofit == null) {
  9. sMovieRetrofit = new MovieRetrofit();
  10. }
  11. }
  12. }
  13. return sMovieRetrofit;
  14. }
  15. private MovieRetrofit() {
  16. Retrofit retrofit = new Retrofit.Builder().baseUrl("http://douban.uieee.com/v2/movie/")
  17. .addConverterFactory(GsonConverterFactory.create())
  18. .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  19. .build();
  20. // 创建网络接口代理
  21. mApi = retrofit.create(Api.class);
  22. }
  23. // 返回API接口对象的实现
  24. public Api getApi() {
  25. return mApi;
  26. }
  27. }

使用单例模式获取Retrofit实例对象, 实现Api的接口,获取接口实例对象.

4)发送网络请求刷新列表

接下来就可以使用接口获取一个Observable对象,通过subscribeOn指定网络请求以及网络响应解析的线程,通过ObserverOn指定刷新UI的线程,实现如下:

  1. /**
  2. * 简化代码,Activity继承自ListActivity
  3. */
  4. public class MovieListActivity extends ListActivity {
  5. private static final String TAG = "MovieListActivity";
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. // 获取Observable对象,查询排名前25的电影
  10. Observable<MovieBean> movieBeanObservable = MovieRetrofit.getInstance().getApi().listTop250(0, 25);
  11. movieBeanObservable.subscribeOn(Schedulers.io())
  12. // 将网络结果转为电影名的集合
  13. .map(new Function<MovieBean, List<String>>() {
  14. @Override
  15. public List<String> apply(MovieBean movieBean) throws Exception {
  16. List<String> array = new ArrayList<String>();
  17. for (int i = 0; i < movieBean.getSubjects().size(); i++) {
  18. String title = movieBean.getSubjects().get(i).getTitle();
  19. Log.d(TAG, "apply: " + title);
  20. array.add(title);
  21. }
  22. return array;
  23. }
  24. })
  25. .observeOn(AndroidSchedulers.mainThread())
  26. .subscribe(new Observer<List<String>>() {
  27. @Override
  28. public void onSubscribe(Disposable d) {
  29. }
  30. @Override
  31. public void onNext(List<String> value) {
  32. ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(MovieListActivity.this,
  33. android.R.layout.simple_list_item_1, value);
  34. setListAdapter(arrayAdapter); // 设置Adapter刷新列表
  35. }
  36. @Override
  37. public void onError(Throwable e) {
  38. Toast.makeText(MovieListActivity.this, "onError",
  39. Toast.LENGTH_SHORT).show();
  40. Log.d(TAG, "onError: " + e.getLocalizedMessage());
  41. }
  42. @Override
  43. public void onComplete() {
  44. Toast.makeText(MovieListActivity.this, "onComplete",
  45. Toast.LENGTH_SHORT).show();
  46. }
  47. });
  48. }
  49. }

Retrofit和RxJava结合后,就可以使用RxJava对结果进行一系列的操作,当需要对网络结果做一些复杂的处理时,RxJava的优势非常大.

更多RxJava在Android平台的使用,可以参考开源项目:

RxJava-Android-Samples

最后给出用到的实体类MovieBean(实体类比较复杂,建议使用Json网站去自动根据Json数据生成Java Bean.)

 

  1. public class MovieBean {
  2. private int count;
  3. private int start;
  4. private int total;
  5. private String title;
  6. private List<SubjectsBean> subjects;
  7. public int getCount() {
  8. return count;
  9. }
  10. public void setCount(int count) {
  11. this.count = count;
  12. }
  13. public int getStart() {
  14. return start;
  15. }
  16. public void setStart(int start) {
  17. this.start = start;
  18. }
  19. public int getTotal() {
  20. return total;
  21. }
  22. public void setTotal(int total) {
  23. this.total = total;
  24. }
  25. public String getTitle() {
  26. return title;
  27. }
  28. public void setTitle(String title) {
  29. this.title = title;
  30. }
  31. public List<SubjectsBean> getSubjects() {
  32. return subjects;
  33. }
  34. public void setSubjects(List<SubjectsBean> subjects) {
  35. this.subjects = subjects;
  36. }
  37. public static class SubjectsBean {
  38. private RatingBean rating;
  39. private String title;
  40. private int collect_count;
  41. private String original_title;
  42. private String subtype;
  43. private String year;
  44. private ImagesBean images;
  45. private String alt;
  46. private String id;
  47. private List<String> genres;
  48. private List<CastsBean> casts;
  49. private List<DirectorsBean> directors;
  50. public RatingBean getRating() {
  51. return rating;
  52. }
  53. public void setRating(RatingBean rating) {
  54. this.rating = rating;
  55. }
  56. public String getTitle() {
  57. return title;
  58. }
  59. public void setTitle(String title) {
  60. this.title = title;
  61. }
  62. public int getCollect_count() {
  63. return collect_count;
  64. }
  65. public void setCollect_count(int collect_count) {
  66. this.collect_count = collect_count;
  67. }
  68. public String getOriginal_title() {
  69. return original_title;
  70. }
  71. public void setOriginal_title(String original_title) {
  72. this.original_title = original_title;
  73. }
  74. public String getSubtype() {
  75. return subtype;
  76. }
  77. public void setSubtype(String subtype) {
  78. this.subtype = subtype;
  79. }
  80. public String getYear() {
  81. return year;
  82. }
  83. public void setYear(String year) {
  84. this.year = year;
  85. }
  86. public ImagesBean getImages() {
  87. return images;
  88. }
  89. public void setImages(ImagesBean images) {
  90. this.images = images;
  91. }
  92. public String getAlt() {
  93. return alt;
  94. }
  95. public void setAlt(String alt) {
  96. this.alt = alt;
  97. }
  98. public String getId() {
  99. return id;
  100. }
  101. public void setId(String id) {
  102. this.id = id;
  103. }
  104. public List<String> getGenres() {
  105. return genres;
  106. }
  107. public void setGenres(List<String> genres) {
  108. this.genres = genres;
  109. }
  110. public List<CastsBean> getCasts() {
  111. return casts;
  112. }
  113. public void setCasts(List<CastsBean> casts) {
  114. this.casts = casts;
  115. }
  116. public List<DirectorsBean> getDirectors() {
  117. return directors;
  118. }
  119. public void setDirectors(List<DirectorsBean> directors) {
  120. this.directors = directors;
  121. }
  122. public static class RatingBean {
  123. private int max;
  124. private double average;
  125. private String stars;
  126. private int min;
  127. public int getMax() {
  128. return max;
  129. }
  130. public void setMax(int max) {
  131. this.max = max;
  132. }
  133. public double getAverage() {
  134. return average;
  135. }
  136. public void setAverage(double average) {
  137. this.average = average;
  138. }
  139. public String getStars() {
  140. return stars;
  141. }
  142. public void setStars(String stars) {
  143. this.stars = stars;
  144. }
  145. public int getMin() {
  146. return min;
  147. }
  148. public void setMin(int min) {
  149. this.min = min;
  150. }
  151. }
  152. public static class ImagesBean {
  153. private String small;
  154. private String large;
  155. private String medium;
  156. public String getSmall() {
  157. return small;
  158. }
  159. public void setSmall(String small) {
  160. this.small = small;
  161. }
  162. public String getLarge() {
  163. return large;
  164. }
  165. public void setLarge(String large) {
  166. this.large = large;
  167. }
  168. public String getMedium() {
  169. return medium;
  170. }
  171. public void setMedium(String medium) {
  172. this.medium = medium;
  173. }
  174. }
  175. public static class CastsBean {
  176. private String alt;
  177. private AvatarsBean avatars;
  178. private String name;
  179. private String id;
  180. public String getAlt() {
  181. return alt;
  182. }
  183. public void setAlt(String alt) {
  184. this.alt = alt;
  185. }
  186. public AvatarsBean getAvatars() {
  187. return avatars;
  188. }
  189. public void setAvatars(AvatarsBean avatars) {
  190. this.avatars = avatars;
  191. }
  192. public String getName() {
  193. return name;
  194. }
  195. public void setName(String name) {
  196. this.name = name;
  197. }
  198. public String getId() {
  199. return id;
  200. }
  201. public void setId(String id) {
  202. this.id = id;
  203. }
  204. public static class AvatarsBean {
  205. private String small;
  206. private String large;
  207. private String medium;
  208. public String getSmall() {
  209. return small;
  210. }
  211. public void setSmall(String small) {
  212. this.small = small;
  213. }
  214. public String getLarge() {
  215. return large;
  216. }
  217. public void setLarge(String large) {
  218. this.large = large;
  219. }
  220. public String getMedium() {
  221. return medium;
  222. }
  223. public void setMedium(String medium) {
  224. this.medium = medium;
  225. }
  226. }
  227. }
  228. public static class DirectorsBean {
  229. private String alt;
  230. private AvatarsBean avatars;
  231. private String name;
  232. private String id;
  233. public String getAlt() {
  234. return alt;
  235. }
  236. public void setAlt(String alt) {
  237. this.alt = alt;
  238. }
  239. public AvatarsBean getAvatars() {
  240. return avatars;
  241. }
  242. public void setAvatars(AvatarsBean avatars) {
  243. this.avatars = avatars;
  244. }
  245. public String getName() {
  246. return name;
  247. }
  248. public void setName(String name) {
  249. this.name = name;
  250. }
  251. public String getId() {
  252. return id;
  253. }
  254. public void setId(String id) {
  255. this.id = id;
  256. }
  257. public static class AvatarsBean {
  258. private String small;
  259. private String large;
  260. private String medium;
  261. public String getSmall() {
  262. return small;
  263. }
  264. public void setSmall(String small) {
  265. this.small = small;
  266. }
  267. public String getLarge() {
  268. return large;
  269. }
  270. public void setLarge(String large) {
  271. this.large = large;
  272. }
  273. public String getMedium() {
  274. return medium;
  275. }
  276. public void setMedium(String medium) {
  277. this.medium = medium;
  278. }
  279. }
  280. }
  281. }
  282. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/300732
推荐阅读
相关标签
  

闽ICP备14008679号