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

原创 2016年06月28日 13:46:46

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执行请求并解析数据。没了!还是很方便的有木有。
写的有点晕,有兴趣看下代码估计更好理解- -,其它的网络缓存和请求取消控制管理看具体业务怎么处理再加上去。

Retrofit 最简单的快速入门及自己封装

简单介绍及官方文档的坑 官方文档 http://square.github.io/retrofit/ Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底...
  • zhiyuan0932
  • zhiyuan0932
  • 2017年01月10日 23:22
  • 17954

使用Retrofit2封装适用于组件化项目的网络库

Android组件化项目HttpClient的封装过程这篇文章主要讲解Android组件化项目中的网络请求工具类HttpClient的封装过程,首先简单介绍了Url和Http请求的概念,接下来讲解了R...
  • guiying712
  • guiying712
  • 2017年07月05日 14:14
  • 3063

Retrofit--合理封装回调能让你的项目高逼格

绪论前面我们讨论了使用Retrofit时怎样去设置OKHttp,包括持久化管理Cookie、设置网络超时、设置打印拦截器、设置缓存、Header等等,详细可查看 Retrofit–使用Retrofi...
  • lyhhj
  • lyhhj
  • 2016年06月20日 14:05
  • 17404

RxJava+Retrofit+OkHttp 深入浅出-终极封装一

背景 之前学习完Retrofit+Rxjava之后写了一篇关于封装的博客,发出后受到大家的关注以及使用,由于不断的完善之前的项目,所以决定把最新的项目封装过程讲解出来,供大家查看!  原博客地...
  • yangxi_001
  • yangxi_001
  • 2017年06月12日 11:38
  • 969

Retrofit项目封装使用

一、概述1、Retrofit开源项目地址2、Retrofit项目官网上官网可能要梯子,大家自备,官网上有它的一系列基本用法,以及他的介绍:A type-safe HTTP client for And...
  • Zzz_Zzz_Z
  • Zzz_Zzz_Z
  • 2016年07月13日 00:15
  • 4505

Android 网络框架 Retrofit2.0介绍、使用和封装

前言 时至今日,Android的网络框架不再像之前那么到处都是,随着Google把 HttpClient直接删掉,似乎意味着Android越来越成熟。网络框架中的佼佼者Volley也不再那么光鲜,取...
  • u014099894
  • u014099894
  • 2016年05月20日 20:44
  • 14812

android EasyRxRetrofit封装(包括上传下载及进度监听)

对RxJava2.X+Retrofit2.X的封装,轻松实现请求、带进度监听的文件上传、带进度监听的文件下载。...
  • anyfive
  • anyfive
  • 2017年06月19日 17:10
  • 676

Android基于Retrofit2.0 封装的超好用的RetrofitClient工具类(完美结合RxJava)

原文地址 :http://www.jianshu.com/p/29c2a9ac5abf RetrofitClient 基于Retrofit2.0封装的RetrofitClient. 避免重复...
  • xiaonaihe
  • xiaonaihe
  • 2016年08月10日 10:41
  • 6308

Android基于Retrofit2.0 +RxJava 封装的超好用的RetrofitClient工具类(六)

csdn :码小白 原文地址: http://blog.csdn.net/sk719887916/article/details/51958010 RetrofitClient基于Ret...
  • sk719887916
  • sk719887916
  • 2016年07月19日 17:44
  • 23891

浅谈Retrofit封装-让框架更加简洁易用

尊重他人的劳动成果,转载请标明出处:http://blog.csdn.net/gengqiquan/article/details/52329259, 本文出自:【gengqiquan的博客】不知不觉...
  • gengqiquan
  • gengqiquan
  • 2016年08月26日 15:55
  • 58816
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Retrofit网络通信库简单封装使用
举报原因:
原因补充:

(最多只允许输入30个字)