Rxjava2+okhttp3+Retrofit2封装

来源:互联网 发布:js用for作1 100 编辑:程序博客网 时间:2024/05/19 12:12

这里是Retrofit构造接口的方式,发现重复代码太多,我在网上找了个库,封装了一下,这是改造前部分接口,上次封装的有局限性,那个是根据接口号区分
如果带后缀就不好使了~

public interface UserServiceApi {    @POST("api/login")    Call<Result<User>> login(@Body WechatLoginRequest request);    @POST("version/version")    Call<Result<User>> update(@Body Update request);    @POST("api/logout")    Call<Result> logout(@Body BaseRequest request);    @POST("api/user/info")    Call<Result<User>> getOtherUserInfo(@Body BaseRequest request);}

封装改造后的api如下

public interface Api {    String KEY = "data";    String PATH = "path";    @FormUrlEncoded    @POST("{path}")    Observable<String> runPost(@Path(value = PATH, encoded = true) String path,                               @Field(KEY) String json);    @GET("{path}")    Observable<String> runGet(@Path(value = PATH, encoded = true) String path,                              @Query(KEY) String json);    @Streaming    @GET    Observable<ResponseBody> downFile(@Url() String url, @QueryMap Map<String, String> maps);    @Multipart    //@POST("/")    @POST    Observable<ResponseBody> uploadFiles(@Url() String url, @Part() List<MultipartBody.Part> parts);}

我把请求后缀放到请求实体上,采用注解的形式,测试时最大耗时2毫秒左右,不知道能不能接受这个时间

@Inherited@Documented@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface ObtainPath {    public String value() default "";}

然后每一个请求体必须实现这个注解,首先我需要一个通用的请求体,姑且如下

@ObtainPath("")public class CommonReq implements Serializable {    //里面可以放通用的请求参数    //比如渠道,版本号,等}

现在如何构建接口呢?

比如有如下接口

登录接口:https://api.github.com/user/login
注册接口:https://api.github.com/user/register
列表接口:https://api.github.com/user/list
更新接口:https://api.github.com/user/update
测试接口:https://api.github.com/user/test

这里请求格式是json,我需要构造请求体如下

登录

@ObtainPath("user/login")public class LoginReq extends CommonReq {    public String name; // 用户名    public String password; // 密码}

注册

@ObtainPath("user/register") // 请求后缀在这里public class RegisterReq extends CommonReq {}

列表

@ObtainPath("user/list")public class ListReq extends CommonReq {}

更新

@ObtainPath("user/update")public class UpdateReq extends CommonReq {}

我觉得请求体肯定是少不掉的.响应体通样如此.
项目接口通用结构如下

可能返回这样 { "code": 1, // 我们后台大佬规定,1是成功,不是http code 200 "msg": "", "data": {} }也可能返回这样 { "code": 1, // 我们后台大佬规定,1是成功,不是http code 200 "msg": "", "data": [] }

抽取通用代码

public class CommonResp implements Serializable {    public static final long serialVersionUID = 1L;    public int code;    public String msg;    public boolean isSuccess() {        return code == 1; // 1 成功 -1 失败 -2 退出登录    }}

如果data返回的是对象

public class HttpCommonObjResp<T> extends CommonResp {    private static final long serialVersionUID = 1L;    public T data; // 我喜欢用public,不用get set 方式获取它 }

如果data返回的是数组对象,我定义如下

public class HttpCommonResp<T> extends CommonResp {    public List<T> data;    public List<T> getDatas() {        if (data == null) {            data = new ArrayList<T>();        }        return data;    }}

到此,通用的请求体,通用的响应体已经全部构造完毕

接下来是调用方式:
比如我们的其中一个接口返回数据如下

{    "code": 1,    "msg": "",    "data": {        "id": "4",        "channel": "yingyongbao",        "vnumber": "10",        "url": "http://shangjie888.oss-cn-shanghai.aliyuncs.com/release-v1.6.5-yingyongbao.apk",        "content": "1.修正"        "platform": "android",        "force": 0,        "name": null,        "switch": "1", // 这尼玛关键字,不知道干嘛使的,我一直没用它,可以不关注它,这个字段鬼知道干嘛的....        "versionnum": "1.6.5"    }}

data对象
我需要把这个对象封装,很多接口,需要很多对象,这里我在封装一个基对象,什么都不干,只实现序列化接口,跳转携带对象好用,不用Parcelable接口,懒得写

public class BaseBean implements Serializable {    public String channel; // 呵呵}
public class UpdateResp extends BaseBean {    public String id;    // public String channel; // 这个通用的么,给它爹    public String vnumber;    public String content;    public String name;    public String platform;}

这里算是封装好一个接口的数据了,姑且叫更新接口,怎么调用?

这里有2种方式
1.你可以获取String 自己手动解析
2.你可以指定返回体data

方式一:

HttpRequestFactory.doPost(new UpdateReq(), new ResultCallbackAdapterIs<String>(this) { // this代表activity            @Override            public void doOnError(ApiException ex) {                super.doOnError(ex); // 这里,activity.isFinishing(); 不会走成功和失败回调的                      }            @Override            public void doOnResponse(String response) {                super.doOnResponse(response);                // 自己手动解析            }        }, null); // null 这里填的是加载框,如有需要

方式二:

data 是对象,所以用HttpCommonObjResp<T>T就是data对象

HttpRequestFactory.doPost(new UpdateReq(), new ResultCallbackAdapterIs<HttpCommonObjResp<UpdateResp>>(this) {            @Override            public void doOnResponse(HttpCommonObjResp<UpdateResp> response) {                super.doOnResponse(response);                if (response.isSuccess()) {                    UpdateResp resp = response.data;                } else {                    // error                }            }        }, ll);

如果是这样呢?

{    "code": 1,    "msg": "",    "data":[] // 数组对象,咋弄}

data 是数组对象,所以用HttpCommonResp<T>T就是data数组对象(集合对象)

HttpRequestFactory.doPost(new UpdateReq(), new ResultCallbackAdapterIs<HttpCommonResp<UpdateResp>>(this) {            @Override            public void doOnResponse(HttpCommonResp<UpdateResp> response) {                super.doOnResponse(response);                if (response.isSuccess()) {                    List<UpdateResp> resp = response.data;                    // 看好了,是List<T>接受                } else {                    // error                }            }        }, null); // null这里是加载框,可以不用,但是要有
其中代码关于缓存,暂时并没有处理~~~

这是HttpRequestFactory的核心代码,获取请求后缀

public static <T> void exec(Object obj, ResultCallback<T> mCallback, boolean isPost, ILoadingI mILoadingI) {        if (obj == null) {            throw new RuntimeException("请求体不能为空~");        }        String pathPostfix = "";        if (obj instanceof CommonReq) {            long start = SystemClock.currentThreadTimeMillis();            CommonReq common = (CommonReq) obj;            ObtainPath mObtainPath = common.getClass().getAnnotation(                    ObtainPath.class);            pathPostfix = mObtainPath.value();            long end = SystemClock.currentThreadTimeMillis();            Log.e(TAG, "##解析耗时##" + (end - start) + "##毫秒##" + (end - start) / 1000                    + "##秒##");            if (TextUtils.isEmpty(pathPostfix)) {                throw new RuntimeException("网络请求路径后缀不能为空!~");            }        } else {            throw new RuntimeException("请求类型必须是CommonReq 或者 其子类吆~");        }        if (!Network.isConnected(HttpLib.getContext())) {            // ToastTool.showNetisDead(HttpLib.getContext());            // 没有网络            if (mILoadingI != null && mILoadingI.isShowingI()){                mILoadingI.beginDismiss(); //加载框            }            return;        }        // 发起网络请求 dowork......        // ....        if(isPost){        HttpRequestManager.doPost(pathPostfix, obj, mCallback,mILoadingI);        } else {        HttpRequestManager.doGet(pathPostfix, obj, mCallback,mILoadingI);        } }

用法

    allprojects {        repositories {            ...            maven { url 'https://jitpack.io' }        }    }    dependencies {                compile 'com.github.majunm.http:http:v1.0.31'    }

也可以移步github

源码下载地址

部分日志