Rxjava2+okhttp3+Retrofit2封装

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

优化版本

部分日志

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,382评论 25 707
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,392评论 2 45
  • 2017-5-17 王老七 王老七的美好生活 以上照片摄于今早夜班后~黑夜过去,美好的一天又到来~我的病...
    普通人老七阅读 390评论 3 3
  • 如果说 我们内心的烦恼 都来源于他人的期待 尝试孤单的人 是不是没有任何忧愁 可是 孤单本身 是不是也是一种负重
    五色浮元子_阅读 146评论 0 0
  • 知实解释:知识通过有效的方法去实践才能变成习惯和能力。尽力提供有效的方法这是我简书的初衷。 遇到双11人...
    知方实习惯阅读 148评论 0 0