优雅地封装使用rxjava2+retrofit2发送http请求

优雅地封装使用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等等自己看情况取舍或重写实现。

你可能感兴趣的:(优雅地封装使用rxjava2+retrofit2发送http请求)