乐虎游戏|乐虎国际登录|欢迎你

RXJava的使用<二>

日期:2020-03-01编辑作者:计算机资讯

图片 1vanke service

前言
RxJava和Retrofit也火了一段时间了,不过最近一直在学习ReactNative和Node相关的姿势,一直没有时间研究这些新东西,最近有个项目准备写,打算先用Android写一个Demo出来,却发现Android的世界发生了天翻地覆的变化,EventBus和OKHttp啥的都不见了,RxJava和Retrofit是什么鬼?
好吧,到Github上耐着性子看过了RxJava和Retrofit的介绍和几个Demo,原来Android的大神Jake Wharton为Retrofit这个项目贡献了这么多的代码,没有道理不用了。
如果你对RxJava不熟悉请先看给 Android 开发者的 RxJava 详解这篇文章。
如果你对Retrofit不熟悉就先看Retrofit官网。
当然也有很多RxJava与Retrofit的文章,但是我觉得很多大家都很纠结的功能都没有被总结出来,所以才有了此篇文章。
欢迎大家拍砖。
接下来进入正文,我是从下面几个角度去思考RxJava与Retrofit结合的。
RxJava如何与Retrofit结合
相同格式的Http请求数据该如何封装
相同格式的Http请求数据统一进行预处理
如何取消一个Http请求 -- 观察者之间的对决,Oberver VS Subscriber
一个需要ProgressDialog的Subscriber该有的样子

啊,经过一天的研究对Retrofit和Rxjava终于有了一定的了解,俗话说的好,好好记性不如烂笔头,于是写个笔记,顺便划个水。嘿嘿嘿。

本文不是单独讲Retrofit2(我上一文章关于Retrofit2),至于http 的知识可以去看《图解HTTP》这本简洁的书,主题是:Rxjava2+Retrofit2 实现Android http 请求。

1.RxJava如何与Retrofit结合
1.1 基本页面
先扔出build.gradle
文件的内容
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.2.0' compile 'io.reactivex:rxjava:1.1.0' compile 'io.reactivex:rxandroid:1.1.0' compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4' compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4' compile 'com.google.code.gson:gson:2.6.2' compile 'com.jakewharton:butterknife:7.0.1'}


封装好后Android 中一个Http请求如下:(onFailed 大部分时候不用重写,在baseobserver中一般都是toast 提示错误。但是需要重新定义网络请求失败需要override)

也就是说本文是基于RxJava1.1.0和Retrofit 2.0.0-beta4来进行的。 添加rxandroid是因为rxjava中的线程问题。
下面先搭建一个基本的页面,页面很简单,先来看文件目录结构

1. Retrofit

Retrofit是一个网络请求框架,为啥Retrofit能够在那么多的请求框架中脱引而出呢,个人觉得就是Retrofit的扩展性,集成Rxjava,Gson等,只是一句话的事情,就像chrome一样,以前一直觉得chrome很不好用,但是自从翻了墙,插件一安,瞬间觉得chrom碉堡了,

学习Retrofit第一步,就是要学习Retrofit的语法(从代码的角度来说,就是api),Retrofit由两部分组成,

  1. 第一部分是Retrofit本身,创建一个Retrofit 语法如下:
    Retrofit retrofit = new Retrofit.builder() .baseUrl(baseurl).build();
    这是基本的Retrofit,如果想要扩展的话,只需要添加需要扩展的部分就可以了(比如扩展Gson,okhttp设置,Rxjava等)。
  2. 第二部分是请求的Api,创建一个api语法如下,
    public interface Api{ @Get("index/{id}/{target}") Call(Bean) getIndex(@path("id)String id , @path(target)String target); }
    上面就是一个基本的api的创建,需要记得东西就是,Retroofit的注解,常用注解有,@get(声明一个get请求的call)
    @Post(声明一个post的call)
    @FormUrlEncoded(只有以表单方式提交的时候可以用这个,)
    @Path(填充url中的占位符)
    @Query(填充url中的参数 比如 "/index?id=1&name=job" )
    @File(填充post表单提交请求的单条内容,对应http header 里面appliacation/x-www.....)
    @Body(相当于一个File的集合,然后将全部要submit的数据,放到一个bean里面,Retrofit会自动拆分bean中的每一个K-V,然后一个个放到post请求的body里面,所以这里的bean不需要序列化,bean会被自动转换为json,对应http请求header里面的appliacation/json,)
  3. 当Retrofit与Rxjava一起使用的时候, 需要改变的东西只有,api中的方法的返回值变为Observable<Bean>即可。
  4. 当单独使用Retrofit的时候,代码如下;
    Api api= retrofit.create(Api.class); api.execute();
    上面是Retrofit的同步使用方法;异步使用方法如下
    Api api = retrofit.create(Api.class); api .enqune(new Callback(){ @override void success(Response response){ } @override void error(){ } )

 HttpCall.getApiService().goLoginByRxjavaObserver(loginParams) .compose(RxObservableUtils.applySchedulers .compose(bindToLifecycle //两个compose 合起来就更简洁了 .subscribe(new BaseObserver<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { loginSuccess(loginResult); } //大部分不用override @Override public void onFailure(int code, String message) { super.onFailure(code, message); } });

图片 2

2. Rxjava

Rxjava相对于Retrofit,就比较有难度了,Rxjava源码找个时间研究一哈,现在把自己知道的Rxjava基本用法写下来。
开始之前,先背几个单词,

Subscribe
Subscriber
SubscribeOn

Observer
Observable
Observeon

FunX ----- OnSubscribe
ActionX ---- Subscriber

Subscriber接口与Observer接口的功能相似,并且多了几个功能,所以尽量使用Subscriber,而对于ActionX来说,是对Subscriber的简单封装。
Observable.OnsubScribe 是创建Obervabl时,需要实现的接口,比如:
Observable observable = new Observable(new Observable.OnSubscribe<T>(){ @override public void call(Subscriber<? super T > Subscriber) { //Subscriber 就是观察者,在这里执行oNnext等 }) 这里有一个疑问,就是对于Rxjava的lift方法和这里的这个Call有什么关系。

当Retrofit与Rxjava一起使用的时候,Observable的创建就不需要上面这种方式了,取而代之的是Retrofit的是由create( interface api)的返回值来创建Observable。

其中 .subscribe(new BaseObserver<LoginResult>() 可以知道只是我们需要的http 返回的数据, 范型<T>和我们的Api结构有关,

目录结构

重点:

  1. Rxjava处理数据的各种方法,简直了,
  2. Rxjava的线程切换 ,
    其中 , SubscribeOn只有第一次是生效的,第二次使用SubsribeOn的时候,不会有效果,但是SubscribeOn在一个地方有奇效,那就是配合doOnSubscribe()的时候,讲doOnSubscribe这个方法,就要讲一下Subscriber的Onstart方法,着个方法是Subscriber的一个不需要强制实现的方法,onStart着个方法执行的时间是subscribe之前,onstart执行的线程一定是调用subscribe()着个方法所在的线程,不能设置,但是doOnSubscrib()这个方法可以设置运行线程,并且doOnsubscribe()的执行时间是在subscribe()执行后事件发生之前,而subscribeOn()这个方法如果在doOnSubscribe之后的话,就可以指定doOnSubscribe()这个方法执行的线程。

action 代表一个事件结束
fun 代表一个事件开始?
对于fun和action ,理解他们是接口就可以了,只不过有时候可以用他们来代替subscriber和onsubscribe,

我们项目的api 返回的结构大致如下,大同小异:

activity_main.xml的代码如下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="" xmlns:tools="" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".activity.MainActivity"> <Button android:id="@+id/click_me_BN" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:padding="5dp" android:text="点我" android:textSize="16sp"/> <TextView android:id="@+id/result_TV" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/click_me_BN" android:text="Hello World!" android:textSize="16sp"/></RelativeLayout>

图片 3api result json

MainActivity.java的代码如下:
package com.queen.rxjavaretrofitdemo.activity;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.widget.Button;import android.widget.TextView;import com.queen.rxjavaretrofitdemo.R;import butterknife.Bind;import butterknife.ButterKnife;import butterknife.OnClick;public class MainActivity extends AppCompatActivity { @Bind(R.id.click_me_BN) Button clickMeBN; @Bind(R.id.result_TV) TextView resultTV; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); } @OnClick(R.id.click_me_BN) public void onClick() { getMovie(); } //进行网络请求 private void getMovie(){ }}

这种结构在我接触的项目中是非常的常见,整个结构中只有result 是不同的(json obgj/array),使用泛型<T>来处理就行.

注意不要忘记加网络权限
<uses-permission android:name="android.permission.INTERNET"/>

/** * 这个类和具体的业务api 结构有关,本Demo的API 结构大致如下: * * Created by anylife.zlb@gmail.com on 2016/7/11. */public class HttpResponse<T> { private int code; private String error; private T result; // some set and some get public T getResult() { return result; } public void setResult { this.result = result; }}

1.2 只用Retrofit
我们准备在getMovie方法中进行网络请求,我们先来看看只使用Retrofit是如何进行的。
我们使用豆瓣电影的Top250做测试连接,目标地址为
https://api.douban.com/v2/movie/top250?start=0&count=10

其中的Header 中的通用头部字段Token,UUID,OSVERSION 等通过拦截全局放在Header中。

至于返回的数据格式,大家自己访问下链接就看到了,太长就不放进来了。
首先我们要根据返回的结果封装一个Entity,暂命名为MovieEntity,代码就不贴了。
接下来我们要创建一个接口取名为MovieService,代码如下:
public interface MovieService { @GET("top250") Call<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);}

根据Retrofit的public interface Call<T> extends Cloneable {...}定义,我们知道要定义的Api Service每个http method中retrofit返回的是Call<HttpResponse<T>>, 和rxjava2结合起来返回 基本类型Observable<HttpResponse<T>> 就行了,自己看看Retrofit 的源代码就知道了。泛型 T和具体的Api 有关,重点放在下面和Rxjava2 的结合:

回到MainActivity之中,我们来写getMovie方法的代码
//进行网络请求private void getMovie(){ String baseUrl = "https://api.douban.com/v2/movie/"; Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .build(); MovieService movieService = retrofit.create(MovieService.class); Call<MovieEntity> call = movieService.getTopMovie(0, 10); call.enqueue(new Callback<MovieEntity>() { @Override public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) { resultTV.setText(response.body().toString()); } @Override public void onFailure(Call<MovieEntity> call, Throwable t) { resultTV.setText(t.getMessage()); } });}

public interface ApiService { /** * 获取信息,返回Observable 可以知道是和Rxjava 结合起来用的 */ @GET("api/lebang/staffs/me/detail") Observable<HttpResponse<StaffMsg>> getStaffMsg(); /** * 纯的Retrofit 啊 */ @POST("api/lebang/oauth/access_token1") Call<HttpResponse<LoginResult>> goLoginByRetrofit(@Body LoginParams loginParams);

以上为没有经过封装的、原生态的Retrofit写网络请求的代码。 我们可以封装创建Retrofit和service部分的代码,然后Activity用创建一个Callback作为参数给Call,这样Activity中只关注请求的结果,而且Call有cancel方法可以取消一个请求,好像没Rxjava什么事了,我觉得可以写到这就下班了~
接下来我们要面对的问题是这样的 如果我的Http返回数据是一个统一的格式,例如
{ "resultCode": 0, "resultMessage": "成功", "data": {}}

我们知道Rxjava 中最简单的流处理是这样的:Observable.subscribe;这种流式处理很好理解就是http 请求这件事被订阅观察了。

我们如何对返回结果进行一个统一的处理呢?
另外,我的ProgressDialog的show方法应该在哪调用呢?看样子只能在getMovie()这个方法里面调用了,换个地方发出请求就要在对应的Listener里面写一遍show()的代码,其实挺闹心。
而且错误请求我也想集中处理掉不要贴重复的代码。
我们先来看结合了Rxjava之后,事情有没有变化的可能。当然即便是不用Rxjava,依旧能够做很多的封装,只是比较麻烦。
如需查看项目代码 --> 代码地址:
https://github.com/tough1985/RxjavaRetrofitDemo

我们的重点就是封装处理一下 Observable 和 Observer以获取员工信息为例子就是

选择Tag -> step1
1.3 添加Rxjava
Retrofit本身对Rxjava提供了支持。
添加Retrofit对Rxjava的支持需要在Gradle文件中添加
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'

 ApiService.getStaffMsg() //1.这是observable .subscribeOn(Schedulers.io //2.请求在IO线程 .observeOn(AndroidSchedulers.mainThread; //3观察处理数据在主线程 .subscribe(new Observer<HttpResponse<StaffMsg>>() { // 4.不解释 @Override public void onSubscribe(Disposable d) { } @Override public void onNext(HttpResponse<StaffMsg> response) { } @Override public void onError(Throwable e) { }

当然我们已经添加过了。
然后在创建Retrofit的过程中添加如下代码:
Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build();

你要这样子写也是没有关系的,但是很明显有很多的冗余代码:

这样一来我们定义的service返回值就不在是一个Call了,而是一个Observable
重新定义MovieService
public interface MovieService { @GET("top250") Observable<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);}

  • HttpResponse<T> 返回的数据我们只想要关心T,HttpResponse 其他部分是一样的
  • 没有必要每个接口处理onError ,大部分的Http 的错误异常处理是可以抽取出共性的
  • 订阅的线程和观察的线程都是一样的,也是重复的代码
  • 请求的时候需要一个网络请求的ProgressDialog 的提示怎么办?

getMovie方法改为:
//进行网络请求private void getMovie(){ String baseUrl = "https://api.douban.com/v2/movie/"; Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); MovieService movieService = retrofit.create(MovieService.class); movieService.getTopMovie(0, 10) .subscribeOn(Schedulers.io())) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<MovieEntity>() { @Override public void onCompleted() { Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable e) { resultTV.setText(e.getMessage()); } @Override public void onNext(MovieEntity movieEntity) { resultTV.setText(movieEntity.toString()); } });}

本文由乐虎游戏发布于计算机资讯,转载请注明出处:RXJava的使用<二>

关键词:

先练哪个字帖才能快速入门?

文/晨风暮溪 不晓得我们在练字的经过中有未有蒙受那么些主题材料 问:先练哪个字帖手艺赶快入门? 图表源于互联...

详细>>

Mac & iOS 如何优雅的使用exchange邮箱

虽说小编笔者不是混工具圈的,不过人在江湖混,哪能不说大话用个 Gmail 呢。 本人如今职场小白。二零一八年在Un...

详细>>

学英语必备的APP,你下了呢?

英语APP用来辅助学英语的作用是越来越大了,有很多因为强大的功能而积累的千万数量的用户,但是怎么选择一款自...

详细>>

你和网红只差一个PS的距离,走心分享高逼格修图app

警报!警报! 作者介绍 文/乐应豫 「五一杯」朋友圈摄影大赛即将开赛 酒酿 大家好,又是你们美丽可爱的警花我呀...

详细>>