优雅地封装使用rxjava2+retrofit2发送http请求
一、需要添加的包
implementation 'io.reactivex.rxjava2:rxjava:2.1.6'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'com.google.code.gson:gson:2.8.2'
二、服务器返回的数据格式封装model
1、这里因为返回的实际有效数据Data可能是不确定的数据类型,所以用泛型,使用时指定具体类型。
2、@SerializedName(value = “Status”, alternate = {“status”}),是在Gson把json数据转换的时候对应key的名称,这里的意思是把json中Status或者status都识别为T data。
3、ResultError是另外一个错误信息实体类。
package cn.syninfo.carwork.model;
import com.google.gson.annotations.SerializedName;
/**
* Created by CHHUANG on 2017/11/2.
*/
public class ResultData {
@SerializedName(value = "Status", alternate = {"status"})
private boolean status;
@SerializedName(value = "Data", alternate = {"data"})
private T data;
@SerializedName(value = "Count", alternate = {"count"})
private Integer count;
@SerializedName(value = "Error", alternate = {"error"})
private ResultError error;
public ResultData(boolean status, T data, Integer count, ResultError error) {
this.status = status;
this.data = data;
this.count = count;
this.error = error;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public ResultError getError() {
return error;
}
public void setError(ResultError error) {
this.error = error;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
@Override
public String toString() {
return "ResultData{" +
"status=" + status +
", data=" + data +
", count=" + count +
", error=" + (error==null?error:error.toString()) +
'}';
}
}
返回错误信息实体类
package cn.syninfo.carwork.model;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;
import java.util.List;
/**
* Created by CHHUANG on 2017/11/2.
*/
public class ResultError {
@SerializedName(value = "Code", alternate = {"code"})
private Integer code;
@SerializedName(value = "Message", alternate = {"message"})
private String message;
@SerializedName(value = "MessageDetail", alternate = {"messageDetail"})
private String messageDetail;
@SerializedName(value = "ModelState", alternate = {"modelState"})
private List modelState;
public ResultError(Integer code, String message, String messageDetail, List modelState) {
this.code = code;
this.message = message;
this.messageDetail = messageDetail;
this.modelState = modelState;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
public String getMessageDetail() {
return messageDetail;
}
public void setCode(Integer code) {
this.code = code;
}
public void setMessage(String message) {
this.message = message;
}
public void setMessageDetail(String messageDetail) {
this.messageDetail = messageDetail;
}
public List getModelState() {
return modelState;
}
public void setModelState(List modelState) {
this.modelState = modelState;
}
@Override
public String toString() {
return "ResultError{" +
"code='" + code + '\'' +
", message='" + message + '\'' +
", messageDetail='" + messageDetail + '\'' +
", modelState=" + (modelState==null?modelState:modelState.toString()) +
'}';
}
}
三、封装Retrofit.Builder,同时创建http请求接口
package cn.syninfo.carwork.service;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by CHHUANG on 2017/11/2.
*/
public class AppRequest {
private AppRequest(){}
private static final String BASE_URL = "http://127.0.0.1:8080/";//这里最后一定要有一个/
private Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
//.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//配置rxjava
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())// 针对rxjava2.x
.baseUrl(BASE_URL)
.build();
private AppService service = retrofit.create(AppService.class);
private static AppRequest instance;
public static synchronized AppRequest getInstance(){
if(instance == null)
instance = new AppRequest();
return instance;
}
public AppService getService() {
return service;
}
}
http请求接口
1、@POST(“User/Login”)//服务器请求地址
2、Flowable
package cn.syninfo.carwork.service;
import cn.syninfo.carwork.model.ResultData;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
/**
* Created by CHHUANG on 2017/11/2.
*/
public interface AppService {
/**
* 登录
* //使用@Field模仿表单提交时需要加了@FormUrlEncoded,
* //@Query请求参数。无论是GET或POST的参数都可以用它来实现
* @param username
* @param password
* @return
*/
@FormUrlEncoded
@POST("User/Login")//服务器地址
Flowable> login(@Field("LoginName") String username, @Field("LoginPwd") String password);
}
四、封装rxjava构成compose,一般情况下的请求都可以用。
1、NetWorkUtils.isNetworkConnected(context),这个方法是用来判断是否有网络,放在doOnSubscribe中,会在执行subscribe方法前执行
2、这里要用FlowableTransformer,因为用了rxjava2的Flowable
package cn.syninfo.carwork.service;
import android.content.Context;
import android.widget.Toast;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import cn.syninfo.carwork.R;
import cn.syninfo.carwork.utils.NetWorkUtils;
import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
/**
* Created by CHHUANG on 2017/11/29.
*/
public class ServiceRxSchedulers {
public static FlowableTransformer compose(final Context context) {
return new FlowableTransformer() {
@Override
public Publisher apply(Flowable upstream) {
return upstream.subscribeOn(Schedulers.io())
.doOnSubscribe(new Consumer() {
@Override
public void accept(Subscription subscription) throws Exception {
if (!NetWorkUtils.isNetworkConnected(context)) {//没有网络
Toast.makeText(context, R.string.bad_network, Toast.LENGTH_SHORT).show();
}
}
}).observeOn(AndroidSchedulers.mainThread());
}
};
}
}
五、实现FlowableSubscriber,封装预处理,处理掉可以公共处理的部分,留下ResultData中的data部分给调用端处理,只留下onHandleSuccess方法在new的时候实现它。
package cn.syninfo.carwork.service;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import com.google.gson.JsonObject;
import org.reactivestreams.Subscription;
import java.util.List;
import cn.syninfo.carwork.model.ResultData;
import cn.syninfo.carwork.model.ResultError;
import io.reactivex.FlowableSubscriber;
/**
* Created by CHHUANG on 2017/11/29.
*/
public abstract class ServiceSubscriber implements FlowableSubscriber> {
private static final String TAG = "BaseObserver";
private Context mContext;
public ServiceSubscriber(Context context) {
this.mContext = context.getApplicationContext();
}
@Override
public void onSubscribe(Subscription s) {
s.request(2);//这里一定要写,估计一般情况上大于0就可以了
}
@Override
public void onNext(ResultData resultData) {
if (resultData.isStatus()) {
T t = resultData.getData();
onHandleSuccess(t);
} else {
onHandleError(resultData.getError());
}
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "error:" + e.toString());
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
protected abstract void onHandleSuccess(T t);
protected void onHandleError(ResultError error) {
Toast.makeText(mContext, error.getMessage(), Toast.LENGTH_SHORT).show();
if(error.getCode()==-1){
List errors = error.getModelState();
if(errors!=null && !errors.isEmpty()){
for (JsonObject json : errors){
Log.i(TAG, "onHandleError: "+json.getAsString());
}
}
}
}
}
六、最后调用
下面代码是在fragment中调用的,parentActivity是在getActivity()方法赋值过的全局变量。
//这里new ServiceSubscriber不能写在subscribe()方法中,不然在android studio中会报错。
ServiceSubscriber serviceSubscriber = new ServiceSubscriber(parentActivity) {
@Override
protected void onHandleSuccess(String token) {//登录成功
Log.i(TAG, "onNext: 令牌="+token);
//保存token
//登录成功打开fragment_main
getFragmentManager().beginTransaction().replace(R.id.main_body, new MainFragment()).commit();
parentActivity.setTitle(R.string.app_name);
}
};
AppRequest.getInstance().getService().login(username, password)
.compose(ServiceRxSchedulers.compose(parentActivity))
.subscribe(serviceSubscriber);
七、当然如果有特殊情况,比如要用到嵌套或者要用doOnNext等等自己看情况取舍或重写实现。