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