您的位置:首页 > 理论基础 > 计算机网络

Retrofit网络通信库简单封装使用

2016-06-28 13:46 537 查看
Retrofit 这个网络库相信用过的都能体会到它的强大,这个库本身已经封装的很优雅了,注解使用起来也很方便,这里我再对这个库封装是为了方便公司接口使用而进行的。注意,这里没有使用Rxjava转换,用的是Gson转换,因为公司项目并没有导入Rxjava,所以都用Gson来处理。

源代码地址:https://github.com/Rukey7/RetrofitSample

一般公司的接口返回的数据都有一个固定格式,举个简单例子:

{
"data": {.... },
"msg": "获取数据成功",
"status": "1"
}
这里的字段,status:返回为请求是否成功;msg:描述信息;data:返回的具体请求数据,可能是一个实体或一个列表,上面返回的是一个实体。返回列表的格式如下:

{
"data": [
{.... },
{.... }
],
"msg": "获取数据成功",
"status": "1"
}


一. Retrofit的使用

具体格式有了,下面就开始编写Api接口了。首先定义一个统一格式的返回实体,对照上面的Json格式如下:

public class BaseResponse {

private String status;
private String msg;
private Object data;

public Object getData() {
return data;
}

public void setData(Object data) {
this.data = data;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
}

@Override
public String toString() {
return "BaseResponse{" +
"status='" + status + '\'' +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
这里需要注意的是data字段要用Object不能用String,我用Gson再将String数据解析为实体时会报错,不知道是不是我写的问题,我用fastjson就没问题,所以这里用Object类型。

下面定义两个请求接口,一个返回实体,一个返回列表:

public interface IUserService {

@GET("user/your")
Call<BaseResponse> user(@Query("id") int id);

@GET("users/your/list")
Call<BaseResponse> userList(@Query("param") String param);
}
来看一下我们正常使用流程,比如获取user信息接口:

public void userInfo() {
// 创建Retrofit
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://api.yoururl.com/")
.build();
// 创建IUserService
IUserService userService = retrofit.create(IUserService.class);
// 创建请求
Call<BaseResponse> call = userService.user(10086);
// 执行请求
call.enqueue(new Callback<BaseResponse>() {
@Override
public void onResponse(Call<BaseResponse> call, Response<BaseResponse> response) {
Gson gson = new Gson();
try {
BaseResponse body = response.body();
// 先判断状态值
if (body.getStatus().equals("1")) {
// 将Object对象转化为json字符串
String jsonData = gson.toJson(body.getData());
// 将json字符串转化为对象实体
UserInfo info = gson.fromJson(jsonData, UserInfo.class);
// 判断解析是否成功
if (info == null) {
onFailure(call, new Throwable("对象解析失败"));
} else {
// 获取到数据,开始处理数据
}
} else {
onFailure(call, new Throwable(body.getMsg()));
}
} catch (Exception e) {
onFailure(call, e);
}
}

@Override
public void onFailure(Call<BaseResponse> call, Throwable t) {
// 失败处理
}
});
}
整个代码调用算是正常流程,这里面肯定有很多冗余代码可以提取出来,看下怎么封装让接口使用更简单,下面开始对接口进行封装。

二. 封装接口

首先来把Gson数据处理的功能封装成一个帮助类:

public final class GsonHelper {

private static Gson sGson = new Gson();
private static JsonParser sJsonParser = new JsonParser();

/**
* 将json数据转化为实体数据
* @param jsonData json字符串
* @param entityClass 类型
* @return 实体
*/
public static <T> T convertEntity(String jsonData, Class<T> entityClass) {
T entity = null;
try {
entity = sGson.fromJson(jsonData.toString(), entityClass);
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
return entity;
}

/**
* 将json数据转化为实体列表数据
* @param jsonData json字符串
* @param entityClass 类型
* @return 实体列表
*/
public static <T> List<T> convertEntities(String jsonData, Class<T> entityClass) {
List<T> entities = new ArrayList<>();
try {
JsonArray jsonArray = sJsonParser.parse(jsonData).getAsJsonArray();
for (JsonElement element : jsonArray) {
entities.add(sGson.fromJson(element, entityClass));
}
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
return entities;
}

/**
* 将 Object 对象转为 String
* @param jsonObject json对象
* @return json字符串
*/
public static String object2JsonStr(Object jsonObject) {
return sGson.toJson(jsonObject);
}
}


功能还是比较清晰的,主要就是对泛型的处理,分别提供了转换实体和实体列表两个主要方法,用来转化Gson数据还是很方便的。

接下来对CallBack<BaseResponse>也进行一层封装,如下:

/**
* 对CallBack进行封装
*/
public abstract class RequestCallBack implements Callback<BaseResponse> {

// 请求成功是的状态值
private static final String RESPONSE_SUCC = "1";
// 请求失败是的状态值
private static final String RESPONSE_FAIL = "-1";

// 测试用
public static boolean mIsList = false;

@Override
public void onResponse(Call<BaseResponse> call, Response<BaseResponse> response) {
BaseResponse body = response.body();
_handleResponse(body);
}

@Override
public void onFailure(Call<BaseResponse> call, Throwable t) {
t.printStackTrace();
onError(t.getMessage());
}

/**
* 处理应答
* @param response 应答实体
*/
private void _handleResponse(BaseResponse response) {
try {
if (RESPONSE_SUCC.equals(response.getStatus())) {
// 请求成功才处理数据
onDataObtain(GsonHelper.object2JsonStr(response.getData()));
} else {
onError(response.getMsg());
}
} catch (Exception e) {
if (e.getMessage() == null) {
onError("thread exiting with uncaught exception");
} else {
onError(e.getMessage());
}
}
}

/**
* 获取json数据
* @param jsonData json字符串
* @return
*/
protected abstract void onDataObtain(String jsonData);

/**
* 获取错误数据
* @param errMsg 错误数据
*/
protected abstract void onError(String errMsg);
}
这里主要工作是从BaseResponse实体中提取出data数据,并转换为json字符串格式传给上层进一步处理,这里也对异常情况进行了初步处理。当然,可能根据实际需要对BaseResponse数据进行更加细致的处理,这个就看实际需求来处理了。
下面自定义个监听器用来获取我们需要的数据:

/**
* 请求监听器
*/
public interface OnRequestListener<T> {

/**
* 获取请求实体数据
* @param entity 实体
*/
void onResponse(T entity);

/**
* 请求失败
* @param errorMsg 异常数据
*/
void onFailure(String errorMsg);
}
这个没什么好说明的,就是有个泛型处理,等下用到就知道了。

现在只差一个功能模块,就是把Call请求、Gson数据和OnRequestListener监听器关联起来,下面是这个功能模块的代码:

/**
* 请求处理的通用模块
*/
public final class ServiceHelper {

private ServiceHelper() {
throw new RuntimeException("ServiceHelper cannot be initialized!");
}

/**
* 获取单个实体的处理操作
*
* @param call        请求
* @param entityClass 实体类型
* @param listener    监听器
*/
public static <T> void callEntity(Call<BaseResponse> call, final Class<T> entityClass,
final OnRequestListener<T> listener) {
call.enqueue(new RequestCallBack() {
@Override
protected void onDataObtain(String jsonData) {
T info = GsonHelper.convertEntity(jsonData, entityClass);
if (info == null) {
if (listener != null) {
listener.onFailure("对象解析失败");
}
} else {
if (listener != null) {
listener.onResponse(info);
}
}
}

@Override
protected void onError(String errMsg) {
if (listener != null) {
listener.onFailure(errMsg);
}
}
});
}

/**
* 获取复数实体的处理操作
*
* @param call        请求
* @param entityClass 实体类型
* @param listener    监听器
*/
public static <T> void callEntities(Call<BaseResponse> call, final Class<T> entityClass,
final OnRequestListener<List<T>> listener) {
call.enqueue(new RequestCallBack() {
@Override
protected void onDataObtain(String jsonData) {
List<T> infos = GsonHelper.convertEntities(jsonData, entityClass);
if (infos.size() == 0) {
if (listener != null) {
listener.onFailure("对象解析失败");
}
} else {
if (listener != null) {
listener.onResponse(infos);
}
}
}

@Override
protected void onError(String errMsg) {
if (listener != null) {
listener.onFailure(errMsg);
}
}
});
}
}
这里提供两个方法,一个用来获取单个实体,一个用来获取实体列表,还是很清晰的。这里同样对泛型进行了处理,并把前面几样东西都关联了起来,所有功能都通过这里进入来处理,包括执行请求->解析对象->调用监听回调。

该写的都写好了,下面就看怎么调用了,比如我们要使用获取单个用户信息接口,可以这样写:

/**
* 获取单个实体
* @param id 参数
* @param listener 请求监听
* @return 通信回调接口,用来取消通信
*/
public static Call userInfo(int id, OnRequestListener<UserInfo> listener) {
Call<BaseResponse> call = sUserService.user(id);
ServiceHelper.callEntity(call, UserInfo.class, listener);
return call;
}
获取用户列表接口这样写:

/**
* 获取实体列表
* @param param 参数
* @param listener 请求监听
* @return 通信回调接口,用来取消通信
*/
public static Call userList(String param, OnRequestListener<List<UserInfo>> listener) {
Call<BaseResponse> call = sUserService.userList(param);
ServiceHelper.callEntities(call, UserInfo.class, listener);
return call;
}
可以看到整个实际只要两行代码:生成一个call请求;使用ServiceHelper执行请求并解析数据。没了!还是很方便的有木有。

写的有点晕,有兴趣看下代码估计更好理解- -,其它的网络缓存和请求取消控制管理看具体业务怎么处理再加上去。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: