您当前的位置: 首页 > 

郭梧悠

暂无认证

  • 2浏览

    0关注

    402博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Retrofit的简单封装

郭梧悠 发布时间:2018-11-20 17:45:10 ,浏览量:2

在Retrofit源码分析几篇博文中详细分析了Retrofit的内部原理,本篇再此基础上对Retrofit做了简单的封装。这次封装是基于所在项目中的情况进行的,可能不具有通用性。但是也算是一个基本思路。 如下图: 在这里插入图片描述 在看项目代码的时候发现如上图的接口方法很多,都有一个共性:就是方法参数一样,都是传一个map。不同的地方只是方法名字不同而已。

根据Retrofit源码分析系列博文我们知道每一个接口都会生成一个ServiceMethod对象并缓存起来。在项目中发现了数百个类似的接口,也就是说需要创建数百个ServiceMethod对象。现在有点不合适,所以我就对其进行了改造。

第一步:创建一个通用的post和get接口类,直接上代码:

interface BaseApi {
   //带参数的通用get请求
    @GET()
    Call executeGet( @Url String url, @QueryMap Map maps);
    
     //不带参数的通用get请求
    @GET()
    Call executeGet(@Url String url);
  
    //不带参数的通用post请求
    @POST()
    Call executePost( @Url String url);

  //带参数的通用post请求
    @POST()
    @FormUrlEncoded
    Call executePost( @Url String url, @FieldMap Map maps);

}

上面的get方法和post方法其返回值都是Call,那么我怎么怎么样自动返回所需的JavaBean呢,别急;且看第二步:

第二步:实现通用的get和post请求

先以同步get请求为例,为了转换特定类型的JavaBean,我们必须知道其Type类型,所以具体的get方法如下所示:

BaseApi baseApi = retrofit.create(BaseApi.class);

 //不带参数的同步get请求
  public  T doGetSync(Class type, final String url) {
         //执行接口的get请求
          Call call = baseApi.executeGet(url);
             //执行网络请求
           Response response = call.execute();
          
          //获取baseApi的class对象
          Class clas = baseApi.getClass();
           //获取executeGet的Method对象
            Method method = clas.getMethod("executeGet", new Class[]{String.class});
            //核心方法,查找对应的Converter对象
            Converter converter = retrofit.responseBodyConverter(type, method.getAnnotations());
          //进行对应的JavaBean转换
            if (converter != null) {
                return (T) converter.convert(response.body());
            }
      
        return null;
    }

上面方法关键有两处: 1、执行 baseApi.executeGet(url)方法获取一个Call对象,然后根据这个call对象执行execute同步请求方法,返回Response对象。 2、根据method的注解以及方法参数的type类型,调用retrofit.responseBodyConverter方法来获取对应的Converter对象,执行转换即可。 关键Converter的具体工作流程可查看Retrofit之Converter简单解析

使用起来也很简单:

YourBean bean = doGetSync(YourBean.class,"you api url")

异步请求有点特殊,因为需要回调结果给客户端,所以另外设置了一个接口:

    public interface IResponse {
        void success(D data);

        void failure(Throwable t);

        /**
         * 返回JavaBean的class 对象 return YouBean.class
         * 以此来确定要转换的类型
         * @return
         */
        Type getDataType();
    }

那么一步请求就如下所示:

 public  void doGetAsync(final String url, final IResponse res) {
     Call call = baseApi.executeGet(url);
        try {
           //异步请求
            call.enqueue(new Callback() {
                @Override
                public void onResponse(Call call, Response response) {
                    if (res == null) {
                        return;
                    }
                    try {
                        Class clas = baseApi.getClass();
                        Method method = clas.getMethod("executeGet", new Class[]{String.class});
                        //根据resonse的getDataType来决定返回的类型
                        Converter converter = retrofit.responseBodyConverter(res.getDataType(), method.getAnnotations());
                        if (converter != null) {
                            T data = (T) converter.convert(response.body());
                            res.success(data);
                        }
                    } catch (Exception e) {
                   
                        res.failure(e);
                    }
                }

                @Override
                public void onFailure(Call call, Throwable t) {
                    if (res != null) res.failure(t);
                }
            });

        } catch (Exception e) {
  
            if (res != null) res.failure(e);
        }
    }

代码就是上面的代码,别的不多说了,直接贴如何使用的代码:

doGetAsync("http://api.apiopen.top/singlePoetry", new ZmHttp.IResponse() {
            @Override
            public void success(Bean data) {
                 //请求成功
            }

            @Override
            public void failure(Throwable t) {
               //请求失败
            }

            @Override
            public Class getDataType() {
                return Bean.class;
            }
        });

到此为止,简单的封装挑选完毕。本次封装只是解决了如上文图中代码所示的api方法参数相同而方法名不同,导致方法越来越多的问题。如有不当之处欢迎批评指正。源码稍后风尚

关注
打赏
1663674776
查看更多评论
立即登录/注册

微信扫码登录

0.0384s