美文网首页Android-Rxjava&retrofit&dagger
Rxjava2+okhttp3+Retrofit2封装

Rxjava2+okhttp3+Retrofit2封装

作者: TMAC_EAH | 来源:发表于2017-12-07 20:49 被阅读161次

这里是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,这个不维护了哈哈哈哈哈
源码下载地址

优化版本

部分日志

相关文章

  • Rxjava2+okhttp3+Retrofit2封装

    这里是Retrofit构造接口的方式,发现重复代码太多,我在网上找了个库,封装了一下,这是改造前部分接口,上次封装...

  • Rxjava2+okhttp3+Retrofit2封装(升级版)

    注册请求体 发起请求 初始化函数 tips:关于用HttpCommObjResp 还是...

  • JavaScript面向对象与设计模式

    1. 面向对象 1.1 封装 封装的目的在于将信息隐藏。广义的封装不仅包括封装数据和封装实现,还包括封装类型和封装...

  • 02.OOP面向对象-3.一些理解

    对封装的理解?封装,类本身就是一个封装,封装了属性和方法。方法也是封装,对一些业务逻辑的封装。私有也是封装,将一些...

  • 封装微信小程序请求

    封装wx.request 封装api 封装请求调用

  • python 文件及文件夹的操作和异常捕获

    1、面向对象的特征:封装、继承、多态 1.1、封装: 函数一种封装,封装了一些逻辑代码 类也是一种封装,封装属性和...

  • node学习4

    Nodejs 路由模块封装、封装仿照 express 的路由 Nodejs 路由模块封装 封装仿照 express...

  • 封装组件

    封装tab组件封装曝光加载组件封装轮播组件 代码

  • MVVM在网络中应用(OkHttp+Retrofit+Gson+

    1.封装请求地址常量类 2.封装网络工具类 3.封装接口类 4.封装DTO类——即返回的数据封装模型 5.封装请求...

  • view的封装

    封装view较为简单,封装tableview比较麻烦,封装tableview的方法后面会有。 view的封装 如果...

网友评论

  • dbba93f08796:注册登录等等,如何传值?是我理解的不对吗?
    LoginClass loginClass = new LoginClass();
    loginClass.myUserName="****";
    loginClass.myUserPassword="******";
    HttpRequestFactory.doPost(loginClass, new ResultCallbackAdapterIs<String>(this) {
    dbba93f08796:主要问题是请求体里没有传入的值和参数,后台无法接受参数。
    dbba93f08796:接口就是简单写的测试接口:
    http://118.190.49.201/work/login.php?myUserName=ttnkh21&myPassword=zheng123456
    也支持POST请求。这是返回的数据:
    {"UserLogin2":{"id":"1","uid":"1","username":"ttnkh21","phone":"17717178181","myName":"\u90d1\u5927\u5927","password":"zheng123456","regTime":"1510060060000","sex":"1","Latitude":"1","Longitude":"1"}}
    TMAC_EAH:@ttnkh21
    你把接口发出来,帮你测试下~找下问题~~

本文标题:Rxjava2+okhttp3+Retrofit2封装

本文链接:https://www.haomeiwen.com/subject/lxgjixtx.html