将retrofit2集成到同时具有webservice和http请求的Android项目中的解决方案

来源:互联网 发布:linux cp怎么用 编辑:程序博客网 时间:2024/05/23 05:08

retrofit2集成(webService、http)

适用环境

1、项目中既有webService服务,也有http服务;
2、项目原有服务是webService或者http其中的一种,由于需求变更等原因要更换服务类型,同时要在不影响原来的服务请求的情况下进行网络框架重构;
3、写服务的换人了;<或者服务人员想装逼,彰显他会多种服务语言>

retrofit2简单介绍

retrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端。简单的说就是一种网络请求框架,对okHttp的封装,使用面向接口的方式进行网络请求,利用动态生成的代理类封装了网络接口请求的底层,其将请求返回javaBean,对网络认证 REST API进行了很好对支持此,使用Retrofit将会极大的提高我们应用的网络体验。

【其实自己是看了github上的网络框架使用统计,排名第一的就是retrofit,所以就去稍稍的研究了一下,发现还挺好用,毕竟这热度可不是水军给刷上去的。】

下面就以我自己的项目中的例子来给大家演示一下今天的核心内容:

实例讲解

一、情景重现

为了迎合后台服务人员(以前公司的后台只会写webService)的服务类型,我们移动端选择采用比较常用ksoap网络请求框架来请求webService服务,首先以图片的形式看一下项目中ksoap网络请求的封装类。
封装好的ksoap网络请求帮助类

以上就是原来项目中用到的ksoap网络请求帮助类,看起来也还OK,但是在实际的项目中,每到一次网络请求就要new出来一个handler或者asyncTask去处理网络请求,并且代码写起来很长很冗余,导致一个页面有多个请求的时候,光关于网络请求的代码就一大堆。另外原来的项目也灭有框架可言,基本大部分的代码都在activity或者fragment中,导致界面工作效率过低,代码过于混乱。
【这里有个不大不小的坑,注意图片中红色部分,留着到后面再讲QAQ】

基于这样的情况,项目组经过商议后决定要重构项目,其中就包括网络请求框架。要求在不改变以前程序代码的基础下进行代码重构。所以经过慎重考虑后,决定将retrofit2集成进我们的项目中去。

二、retrofit集成

1、首先导入retrofit2的相关依赖:

    //retrofit网络框架    compile 'com.squareup.retrofit2:retrofit:2.3.0'          //retrofit2.3.0类库    compile'com.squareup.retrofit2:converter-scalars:2.3.0'  //关于字符串的转换器    compile 'com.squareup.retrofit2:converter-gson:2.3.0'    //关于gson的转换器    compile 'com.squareup.okhttp3:logging-interceptor:3.4.1' //okhttpClient的log拦截器

2、http请求:
依赖包导入成功后就可以放肆的利用retrofit2进行实验了,首先用一个简单的http请求测试一下是否能走通。

    public interface PostApi {    /**     * 上传错误信息接口     * */    @POST("api/OPERATION_ERROR_STATISTICS")    Call<ResponseBody> postError(@Body ErrorBean bean);    }

以上是一个简单的post请求接口。
【实体类就不贴了,自定义任何一个实体类都可以】
然后是请求的方法及回调:

 public void errorPost(List<CrashBean> list){        //创建retrofit        Retrofit retrofit = new Retrofit.Builder()                .baseUrl(ActionNet.BASE_URL)                .client(getOkHttpClient())                .addConverterFactory(GsonConverterFactory.create())                 .build();        PostApi api = retrofit.create(PostApi.class);        ErrorBean bean = new ErrorBean();        bean.setData(list);        Call<ResponseBody> call = api.postError(bean);        call.enqueue(new Callback<ResponseBody>() {            @Override            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {                try {                    if(response.body() != null){                        String result = response.body().string();                        Log.e(TAG+"Error", "onResponse: "+result);                    }                } catch (IOException e) {                    e.printStackTrace();                }            }            @Override            public void onFailure(Call<ResponseBody> call, Throwable t) {                Log.e(TAG+"Error", "onFailure: ");            }        });    }

retrofit2的具体实现我就不说了,相信大家都已经了解过retrofit2了。
程序走了一遍可以走通,证明了retrofit2是可以正常使用的。

3、retrofit2请求webService

好了,轮到本文重头戏上场了。
首先,尝试着使用retrofit2请求webService:
【当然对于这个刚开始我是一脸懵逼的,要不是网上有一些关于retrofit2请求webService的文章,我还真的不知道从何下手,毕竟webService的请求接口中注解有点儿复杂】
/**
* 获取补丁版本
* */
@Headers({“Content-Type: text/xml;charset=UTF-8”, “SOAPAction: http://tempuri.org/getNewAppPatch“}) //请求的Action,类似于方法名
@POST(“GetTJWebService.asmx”)
Call getNewAppPatch(@Body String envelope);

看到webService请求接口里的请求头了吧,超复杂的感觉。【注意我的请求实体类是String,使用String是为了所有的请求都能公用一个类,所以就把实体类转换成String并进行封装(当然simplexml的转换器可以自动将实体类进行解析,但是这样太麻烦,每一个请求都要写一大堆转换类)】
首先要知道webService服务是以xml的形式进行请求并返回数据,这里给大家贴一下webService的请求
webService请求
webService返回

可以看到,webService的请求和返回都是有固定格式的要求(这里用的是soap1.1版本),所以这里为了使所有的webService请求都能适配,我这里封装了一个自定义的请求及返回数据的处理类,即webService的请求和接收都是将参数或者返回数据处理成String字符串进行请求和接收。代码如下:

public class Node {    public static String toStart(String name){        return "&lt;"+name+"@gt;";    }    public static String toEnd(String name){        return "&lt;/"+name+"&gt;";    }    public static String getRequest(String namespace, Map<String,String> map){        StringBuffer sbf = new StringBuffer();        String startStr = "<soap:Envelope   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"                +"  <soap:Body>\n"                +"      <"+namespace+" xmlns=\"http://tempuri.org/\">\n";        sbf.append(startStr);        for (Map.Entry<String,String> entry : map.entrySet()){            sbf.append("            <"+entry.getKey()+">"+entry.getValue()+"</"+entry.getKey()+">\n");        }        String endStr = "       </"+namespace+">\n"                +"  </soap:Body>\n"                +"</soap:Envelope>";        sbf.append(endStr);        return sbf.toString();    }}

这是请求的封装,下面是接收的封装:

public Map<String,String> dealResponse(Response<ResponseBody> response){        Map<String,String> map = new HashMap<>();        String head = response.raw().request().header("SOAPAction");        String url = response.raw().request().url().toString();        String type = null,data = null,res = null;        try {            if(head != null){                                                                   //webService请求                String name = head.replace(AppNet.NAME_SPACE, "");                type = url+"/"+name;                data = response.body().string().replaceAll("&lt;","<").replaceAll("&gt;",">");                res = StringUtils.substringBetween(data,"<"+name+"Result>","</"+name+"Result>");            }else {                                                                             //Http请求                type = url;                data = response.body().string();                res = data;            }        } catch (IOException e) {            e.printStackTrace();        }        map.put("data",res);        map.put("url",type);        return map;    }

这样请求和接收的转换都有了,现在就来测试一下请求webService。
请求接口上面已经贴过了,下一步就是创建retrofit,这里我进行了一下封装。

//创建retrofitpublic void creatRetrofit(){    if(retrofit == null){        OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);        OkHttpClient client = okHttpClient.connectTimeout(2, TimeUnit.MINUTES)                .writeTimeout(2, TimeUnit.MINUTES)                .readTimeout(2, TimeUnit.MINUTES)                .addInterceptor(httpLoggingInterceptor)                .build();        retrofit = new Retrofit.Builder()                .baseUrl(this.BASE_URL)                .addConverterFactory(ScalarsConverterFactory.create())                .addConverterFactory(GsonConverterFactory.create())                .client(client)                .build();    }    if(mService == null){        mService = retrofit.create(UserService.class);    }}

注意:ScalarsConverterFactory一定要加上,不然无法将String字符串转换成xml的请求格式,这个坑我可是看了好久才搞出来,一定要注意细节!
其中UserService是我的接口类。
然后就是发出请求:

public void getVerson(String xml, Callback<ResponseBody> callback){    Call<ResponseBody> call = mService.getNewAppPatch(xml);    call.enqueue(callback);}

请求之后是回调:

    @Override    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {        if(response.body() != null){            map = model.dealResponse(response);            data = map.get("data");            url = map.get("url");            if(model.isWebService(response)){                //进行xml解析                switch (url){                    case "":                        break;                }            }else {                //进行json解析                switch (url){                    case "":                        break;                }            }        }else {            Log.e("fail", "requestFailed");        }    }    @Override    public void onFailure(Call<ResponseBody> call, Throwable t) {        Log.e("error", "requestError");    }

【这里的回调和上面的返回数据转换,我把webService和http都进行了区分,这样不管是webService还是http都可以公用一个回调,适用于一个页面既有webService也有http请求,并且都是多个请求。】

本以为这样就可以万事大吉,但是点一下运行,程序报错了,我们来看看报错内容吧:
报错信息

一目了然,依赖包冲突,而且是OkHttp3的依赖包冲突。心想,我的项目里没有导入OkHttp啊,哪来的冲突?于是乎我就在项目中进行寻找,还真让我找到了:
ksoap的jar包
原来如此,ksoap的jar包里包含了okhttp3,而且retrofit是强制封装了OkHttp3,所以才会有冲突,这样的话就只好去重了啊,我的方法是这样的,把ksoap包里的okhttp3和okio这两个包给删掉,然后我们在文章顶部中soapUtils类里,把红色部分改为HttpTransportSE就可以了。
这里写图片描述
然后再运行,项目完完整整的跑出来了。这就是将retrofit2集成到同时具有webService和http请求的项目中去的解决方案了。

总结

1、把webService的请求和接收封装起来,这样使请求更加方便。
2、在retrofit2请求webService的时候,如果要使用String转换的话一定要加上ScalarsConverterFactory的转换器;
3、ksoap的jar包里是有okhttp请求的,所以retrofit和ksoap会有冲突依赖,根据实际情况解除冲突;
4、本文没有具体的说明retrofit请求http和webService的教程,如果大家不是很了解,建议去看看其他博主的博客,如:
http://blog.csdn.net/lmj623565791/article/details/51304204 retrofit2完全解析
http://www.jianshu.com/p/b865c855a1e8 retrofit2 + OkHttp + WebService请求
5、建议你的后台人员只写一种服务,因为这样的多种请求真是要搞死人QAQ。

本博主第一次写这么长的文章,希望大家多多支持,有什么不对的还希望大家多多指正。
代码还没来得及上传到github,如有需要请留言。
谢谢侬!(鞠躬)

阅读全文
4 1