RxJava + Retrofit2.0的项目实战完美封装

Retrofit 和RxJava已经出来很久了,从去年开始rxjava和retrofit就开始火,所以之前在做项目的时候也用了rxjava和retrofit,今天就介绍一下在项目中如何封装rxjava和retrofit。对于 RxJava 不是很了解的同学推荐你们看这篇文章给 Android 开发者的 RxJava 详解。Retrofit的使用可以看看Android Retrofit 2.0使用。
首先在我们的工程的build.gradle中添加依赖:

compile 'io.reactivex:rxjava:1.1.8' compile 'io.reactivex:rxandroid:1.2.1' compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0'

然后封装retrofit:
public class HttpMethods { //接口根地址 public static final String BASE_URL = "http://www.baidu.com"; //设置超时时间 private static final long DEFAULT_TIMEOUT = 10_000L; private Retrofit retrofit; private OkHttpClient client; private static class SingletonHolder { private static final HttpMethods INSTANCE = new HttpMethods(); } //私有化构造方法 private HttpMethods() { client = new OkHttpClient.Builder() .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS) //添加请求头 //.addInterceptor(new HeaderInterceptor()) //添加日志打印拦截器 .addInterceptor(new LoggerInterceptor("===", true)) .build(); retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .client(client) //添加Gson解析 .addConverterFactory(GsonConverterFactory.create()) //添加rxjava .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); }public static HttpMethods getInstance() { return SingletonHolder.INSTANCE; } //这里返回一个泛型类,主要返回的是定义的接口类 public T createService(Class clazz) { return retrofit.create(clazz); }}

【RxJava + Retrofit2.0的项目实战完美封装】这就是定义的接口类:
/** * 接口定义 */ public interface ApiService {@FormUrlEncoded @POST("/sys/sendMsg") Observable> getData(@FieldMap Map params); }

这里的根地址和接口中的地址都是随便写的一个地址,用的时候替换成自己项目的地址就行了。添加请求头的话,由于项目中没用到所以直接注释了。
接下来就是封装服务器请求和返回数据。一般情况下返回的数据结构是这样的:
{ "status_code":10000, "error_msg":"请求成功!", "data":{ "name":"张三", "age":3 } }

如果你们的服务器返回不是这样的格式那你就只有坐下来请他喝茶,跟他好好说了。大不了就怼他。
对于这样的数据我们肯定要对status_code做出一些判断,不同的status_code对应不同的错误信息。所以我们新建一个BaseEntity,对应上面的数据结构。
public class BaseEntity implements Serializable {private int status_code; private String error_msg; private T data; public T getData() { return data; }public void setData(T data) { this.data = https://www.it610.com/article/data; }public int getStatus_code() { return status_code; }public void setStatus_code(int status_code) { this.status_code = status_code; }public String getError_msg() { return error_msg; }public void setError_msg(String error_msg) { this.error_msg = error_msg; } }

这就是所有实体的一个基类,data可以为任何数据类型,所以我们使用泛型。
我们要对所以返回结果进行预处理,新建一个DefaultTransformer继承Observable.Transformer,预处理无非就是对status_code进行判断和解析,不同的错误返回不同的错误信息。有个操作符compose。因为我们在每一个请求中都会处理status_code以及使用一些操作符,比如用observeOn和subscribeOn来切换线程。RxJava提供了一种解决方案:Transformer(转换器),一般情况下就是通过使用操作符compose()来实现。
代码:
public class DefaultTransformer implements Observable.Transformer { @Override public Observable call(Observable tObservable) { return tObservable .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .map(new Func1() {// 通用错误处理,判断code @Override public T call(T t) { if (((BaseEntity)t).getStatus_code() != 10000) { throw new ApiException(((BaseEntity)t).getStatus_code(), ((BaseEntity)t).getError_msg()); } return t; } }); }public static DefaultTransformer create() { return new DefaultTransformer<>(); } }

这里我们使用map操作符把Obserable< BaseEntity< T > >,转换成为Observable< T >在内部对status_code进行了预处理。这里当状态码不等于10000就表示请求出错抛出异常。这里的ApiException是我们自定义的一个异常类,用来处理服务器返回的异常。
代码:
public class ApiException extends IllegalArgumentException {private int code; public ApiException(int code, String msg) { super(msg); this.code = code; }public int getCode() { return code; } }

接下来就是处理网络请求的操作,和显示加载等待的dialog:
public abstract class ApiSubscriber extends Subscriber {private LoadingDialog mDialog; public ApiSubscriber() {}public ApiSubscriber(@NonNull Context context) { mDialog = new LoadingDialog(context); }@Override public void onStart() { if (mDialog != null) mDialog.show(); }@Override public void onCompleted() { if (mDialog != null && mDialog.isShowing()) mDialog.dismiss(); }/** * 只要链式调用中抛出了异常都会走这个回调 */ @Override public void onError(Throwable e) { if (mDialog != null && mDialog.isShowing()) mDialog.dismiss(); if (e instanceof ApiException) { //处理服务器返回的错误 } else if (e instanceof ConnectException || e instanceof UnknownHostException) { ToastUtils.showShort("网络异常,请检查网络"); } else if (e instanceof TimeoutException || e instanceof SocketTimeoutException) { ToastUtils.showShort("网络不畅,请稍后再试!"); } else if (e instanceof JsonSyntaxException) { ToastUtils.showShort("数据解析异常"); } else { ToastUtils.showShort("服务端错误"); } e.printStackTrace(); } }

这里新建一个ApiSubscriber类继承Subscriber类,写了两个构造方法,一个是显示dialog,一个是不显示dialog。重写了三个方法,这里我们没有重写onNext方法,因为这个方法是请求成功返回数据的,所以我们等到请求数据界面去重写。在onError里面做了所有的错误处理,在里面可以根据服务器返回的错误码对不同的错误做不同的处理。
接下来的话就是管理生命周期了。有个专门的库可以管理生命周期的叫RxLifecycle,可以去看看。不过我们不用这个,我们在BaseActivity里面写。
public abstract class BaseActivity extends AppCompatActivity {private CompositeSubscription mCompositeSubscription; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }@Override protected void onDestroy() { super.onDestroy(); onUnsubscribe(); } /** * 所有rx订阅后,需要调用此方法,用于在detachView时取消订阅 */ protected void addSubscription(Subscription subscribe) { if (mCompositeSubscription == null) mCompositeSubscription = new CompositeSubscription(); mCompositeSubscription.add(subscribe); }/** * 取消本页面所有订阅 */ protected void onUnsubscribe() { if (mCompositeSubscription != null && mCompositeSubscription.hasSubscriptions()) { mCompositeSubscription.unsubscribe(); } }}

我们在请求数据的地方调用addSubscription(Subscription subscribe)方法,当activity在onDestroy()的时候就取消订阅了。
最后就是我们的请求数据了,这是之前定义的一个伪接口:
public interface ApiService {@FormUrlEncoded @POST("/sys/sendMsg") Observable> getData(@FieldMap Map params); }

然后我们在activity里面这样写:
public class MainActivity extends BaseActivity {private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv_content); findViewById(R.id.btn_request).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { getData(); } }); }private void getData() { Map params = new HashMap<>(); params.put("user_name", ""); params.put("user_pwd", ""); Subscription subscribe = HttpMethods.getInstance() .createService(ApiService.class) .getData(params) .compose(DefaultTransformer.>create()) .subscribe(new ApiSubscriber>(this) { @Override public void onNext(BaseEntity entity) {} }); addSubscription(subscribe); //添加订阅 } }

在onNext方法里面就能获取到我们的数据了,当然这个接口是请求不成功的,在使用的时候替换成自己的接口就行了。retrofit还有很多的注解,这里只是使用了@FormUrlEncoded注解(表单的形式)做个示例。到这里封装就基本完成了,我也是菜鸟,希望大家多提意见,互相学习。
源码地址

    推荐阅读