Retrofit使用中有关OkHttp的一些事

废话部分

只是在工作上的一些无聊的事情,想闲扯的可以看下,不想的可以用直接看下一段的正题。
我是两个月前换的一个工作,去的一个公司只有我一个人开发,并且是从零开始,什么都没有的情况下我还是去了,因为我个人觉得这个机会不错,以前工作了两年都是copy别人的代码或者维护别人的代码。项目也是不伦不类的MVC,网络请求、缓存、项目架构现在看来都是糟的一塌糊涂(现在这么认为,因为这两个月自己感觉自己有了很多提高),不过当时的我竟然那么安逸的选择在那里一直待下去,很庆幸自己已经出来了,不然面对现在这么激烈的竞争,我想我可能就被市场淘汰了。可能现在还有很多人在一个比较安逸的公司拿着不错的薪资一直没有跳槽的想法,我只是给大家一个建议,如果你喜欢技术,喜欢挑战,建议早些脱离这些公司,把每个公司当成自己技术增长的跳板,不过不建议不到一年就换工作的,太频繁了也不好,最起码要把这个公司用到的技术全部学到了才能走,不然到最后还是很难学到东西。好了不废话了。开始今天的正题了。

Retrofit??

现在Retrofit可能很多人都有了解,毕竟现在很多开发者社区到处可见的标题都是Retrofit+RxJava+MVP这些文章,刚开始自己看这些的时候也有些懵,不过多研究一下,在项目中用一下就发现其实这些东西都不是很难,给开发者一些建议,别上来就去看一些开源项目的源码,那样你会一头懵逼的,大家可以尝试去了解应用场景,尝试在项目中或者自己写个东西去实践一下,然后再去看源码。
Retrofit通俗的说就是一个HTTP请求的一个框架,通过一个Interface来定义api的实现,通过注释的方式进行一些请求的设置。

public interface GitHubService 
{
    @GET("users/{user}/repos") 
    Call<List<Repo>> listRepos(@Path("user") String user);
}

就像上面的代码一样,所有的网络请求接口都是定义在一个Interface中,然后在使用的时候通过Retrofit中的create()方法即可实现,详细的可以看
[Retrofit官网](http://square.github.io/retrofit/
[Retrofit api文档](http://square.github.io/retrofit/2.x/retrofit/
有关Retrofit的在这里不多说,因为本篇主要是来说在使用过程中有关OkHttp的事情,所以想了解Retrofit的可以去查询其他的资料

Retrofit中OkHttp使用

大家都知道Retrofit中默认使用的网络请求方式是使用OkHttp的,先了解下OkHttp
OkHttp的官网介绍和Retrofit很像,也是一个基于Http的一个请求客户端,毕竟Retrofit和OkHttp都是square的开源项目,下面来说下我在项目里面使用的时候有关okhttp的配置问题。
首先okhttp的确非常棒,在接入到项目里面使用的时候日志输入非常详细,类似Content-type,header、参数返回值这些全部都很详细的显示,Okhttp最棒的一个设计就是整个网络请求过程中我们可以用在任意一个地方去做一个拦截处理,我们可以通过实现提供的接口[Interceptor](http://square.github.io/okhttp/3.x/okhttp/okhttp3/Interceptor.html
下面我来举个例子:
我在和我们后台人员沟通的时候发现我们每个接口都有两个共同的参数 version和device,我们不可能在定义的时候每个接口里面都去添加上这两个参数,为了方便我们会在一个地方统一的去添加,那么我们就可以通过自定义一个Interceptor来实现,具体代码如下:

public class CommonParamsInterceptor implements Interceptor
{
    @Override
    public Response intercept(Chain chain) throws IOException
    {
        Request request = chain.request();
        //get请求后面追加共同的参数
        HttpUrl httpUrl = request.url().newBuilder()
                                 .addQueryParameter("version", ConstantConfig.APP_VERSION_CODE)
                                 .addQueryParameter("token", ConstantConfig.APP_TOKEN)
                                 .addQueryParameter("device", "Android").build();
        request = request.newBuilder().url(httpUrl).build();
        return chain.proceed(request);
    }
}

这样就可以实现每个请求上面添加上参数,不过有些事情总是比你想象的蛋疼一些,因为后台接口是两个人开发的,一个人告诉我所有的请求方法是get和post都支持,当时这样写也没发现什么问题,后台和另一个人调试的时候发现不行,找了半天原因才发现原来上面的写法是吧这些参数都放到了url的后面,也就是get请求的传参方式,所以如果限定了必须使用post请求那么这个方法就不行了。唉。。。没办法,只能去修改,然后就是一番查找,终于解决了,代码如下:

public class CommonParamsInterceptor implements Interceptor
{
    @Override
    public Response intercept(Chain chain) throws IOException
    {
        Request request = chain.request();
        //post请求追加参数
        FormBody.Builder newBody = new FormBody.Builder();
        newBody.add("version", ConstantConfig.APP_VERSION_CODE)
               .add("token", ConstantConfig.APP_TOKEN).add("device", "Android").build();
        //拦截请求中用户传入的数据,把参数遍历放入新的body里面,然后进行一块提交
        FormBody oldBody = (FormBody) request.body();
        for (int i = 0; i < oldBody.size(); i++)
        {
            newBody.add(oldBody.encodedName(i), oldBody.encodedValue(i));
        }
        request = request.newBuilder().post(newBody.build()).build();
        chain.proceed(request);
    }
}

这样就实现了表单数据的提交,get和post的设置共同参数的方式。从这一个例子就可以看出使用okhttp的时候我们可以在每一个步骤进行拦截处理,比如设置缓存、头部信息等等。
自定义的Interceptor可以在初始化okhttp的时候设置,如:

 /**
     * OkHttp的初始化,设置缓存目录,设置请求最大时间,请求失败重连
     */
    public void initOkHttp()
    {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        CustomParamsInterceptor paramsInterceptor = new CustomParamsInterceptor();
        builder.addInterceptor(paramsInterceptor);
        if (BuildConfig.DEBUG)
        {
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            builder.addInterceptor(loggingInterceptor);
        }
        // 缓存 http://www.jianshu.com/p/93153b34310e
        File cacheFile = new File(ConstantConfig.CACHE_DIR, "/NetCache");
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
        Interceptor cacheInterceptor = new Interceptor()
        {
            @Override
            public Response intercept(Chain chain) throws IOException
            {
                Request request = chain.request();
                if (!Util.isNetworkConnected(App.getmAppContext()))
                {
                    request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
                }
                Response response = chain.proceed(request);
                if (Util.isNetworkConnected(App.getmAppContext()))
                {
                    int maxAge = 0;
                    // 有网络时 设置缓存超时时间0个小时
                    response.newBuilder().header("Cache-Control", "public, max-age=" + maxAge)
                            .build();
                } else
                {
                    // 无网络时,设置超时为4周
                    int maxStale = 60 * 60 * 24 * 28;
                    response.newBuilder().header("Cache-Control",
                                                 "public, only-if-cached, max-stale=" + maxStale)
                            .build();
                }
                return response;
            }
        };
        builder.cache(cache).addInterceptor(cacheInterceptor);
        //设置超时
        builder.connectTimeout(15, TimeUnit.SECONDS);
        builder.readTimeout(20, TimeUnit.SECONDS);
        builder.writeTimeout(20, TimeUnit.SECONDS);
        //错误重连
        builder.retryOnConnectionFailure(true);
        okHttpClient = builder.build();
    }

okhttp很方便,很灵活,我们可以随意的折腾。不过,话说,最气人的是因为ios那边的问题,接口竟然要求我参数的传递用json格式。

这里为大家说下数据传输格式和数据格式是两个不同的东西,我们一般认为数据格式使我们手机在接收接口api返回的数据是一个json的String串,但是和后台接口传递数据的格式有以下几种:

  • application/xhtml+xml :XHTML格式
  • application/xml : XML数据格式
  • application/atom+xml :Atom XML聚合格式
  • application/json : JSON数据格式
  • application/pdf :pdf格式
  • application/msword : Word文档格式
  • application/octet-stream : 二进制流数据(如常见的文件下载)
  • application/x-www-form-urlencoded : <form encType=””>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)

我们在不设置默认的情况下http请求的数据传输格式是最后一个application/x-www-form-urlencoded ,这个设置是一key value的形式传递的参数,但是我们的后台要求我使用application/json的格式去传递数据,唉。。。。那以上两种方法就不可行了,没办法,接着一番,最终也是搞出来了,代码如下:

public class CustomParamsInterceptor implements Interceptor
{
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    @Override
    public Response intercept(Chain chain) throws IOException
    {
        Request request = chain.request();
        ArrayMap<String, String> paramsMap = new ArrayMap<String, String>();
        paramsMap.put("version", "1.0");
        paramsMap.put("token", "");
        paramsMap.put("device", "Android");
        if (request.body() instanceof FormBody)
        {
            FormBody oldBody = (FormBody) request.body();
            for (int i = 0; i < oldBody.size(); i++)
            {
                paramsMap.put(oldBody.encodedName(i), oldBody.encodedValue(i));
            }
        }
        Gson gson = new Gson();
        AppLog.i("Gson参数格式---" + gson.toJson(paramsMap));

        RequestBody body = RequestBody.create(JSON, gson.toJson(paramsMap));
        request = request.newBuilder().post(body).build();
        return chain.proceed(request);
    }

}

这就是我今天所有的经历了,我每天都会写一篇关于在开发中遇到的问题和学到的技术点,如果有兴趣的可以关注,虽说现在还是个小白,不过努力总不会白费的,加油吧骚年们。
我的项目使用了MVP+RxJava+Retrofit 很多东西都还在持续的完善中,如果有兴趣的大家可以一起讨论。感谢大家的阅读。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,279评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,566评论 18 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,836评论 6 13
  • 阿丧来我家快有一个月了。他第一次出现在院子里时,着实把大家吓了一跳。手臂上的伤口已经腐烂,可怖的青筋爬到了太阳穴,...
    子愈阅读 592评论 2 2
  • 失败的人,往往有十误 一聪明误 有些人失败,是因为不够聪明。有些人失败,则是因为太聪明。后一种人的失败,就叫聪明误...
    酷聊析曼阅读 422评论 0 0