Android 网络框架_目前(2016年11月7日)最流行的网络框架OKHttp3

现在每篇文章前都会吐槽下自己的生活事情,也当作个记录,本来想写这篇博客很久的了,看标题就知道,想 11 月 7 日就开始写的了,可是现在(2016年11月27日22:45:12)还没写完,因为这段事件赶公司的即时聊天的项目,还有每个星期都会来一篇算法的文章或做算法的题,因此导致这篇文章很久还没写完,不想拖下去,赶紧写完。


一、 OKHttp基础

我们可以通过右键 new——》Module——》java Library 的方式来创建一个 Module 的方式来测试一下 OKHttp3 ,为什么是创建 java Library 呢?因为对于一般的网络框架而已,我们只需要创建 java Library就可以了,不必要创建 Android Library 。

然后导入我们的OKHttp3,具体的官网在之前的系列文章中就有个介绍:
CSDN:http://blog.csdn.net/Two_Water/article/details/53055524
简书:http://www.jianshu.com/p/049a91e9958a

创建lib

1.同步请求和异步请求

创建完项目后,来了解一下OKHttp3的同步请求和异步请求,虽然官网就有很详细的例子,可是最好还是自己读尝试一次,就算是跟着官网的例子敲一遍,还是有一番体会的。


package com.liangdianshui.http.lib;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * OKHttp 同步请求和异步请求
 *
 * Created by liangdianshui on 2016/11/8
 */
public class SendRequest {

    /**
     * 同步请求
     * <p>
     * 会阻塞当前线程
     * </p>
     *
     * @param url
     */
    public static void sendRequest(String url) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println(response.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 异步请求
     *
     * @param url
     */
    public static void sendAsyncRequest(String url) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    System.out.println(Thread.currentThread().getId());
                }
            }
        });
    }

    public static void main(String args[]) {
        sendRequest("http://blog.csdn.net/two_water");
        System.out.println("-------------------------------------------");
        System.out.println(Thread.currentThread().getId());
        sendAsyncRequest("http://blog.csdn.net/two_water");

    }
}


2.请求头和响应头

在上一个博客中也有介绍到响应头和请求头,也介绍了一大堆参数,那么我们如何使用这些参数呢?


package com.liangdianshui.http.lib;

import java.io.IOException;

import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * 增加请求头的请求
 * Created by liangdianshui on 2016/11/8
 */
public class AddHeaderRequest {

    public static void addHeaderRequest(String url) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .addHeader("User-Agent", "liangdianshui")
                .build();
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                Headers requestHeaders = request.headers();
                System.out.println("----------Request Headers------------");
                for (int i = 0; i < requestHeaders.size(); i++) {
                    System.out.println(requestHeaders.name(i) + " : " + requestHeaders.value(i));
                }

                Headers responseHeaders = response.headers();
                System.out.println("------------Response Headers-----------");
                for (int i = 0; i < responseHeaders.size(); i++) {
                    System.out.println(responseHeaders.name(i) + " : " + responseHeaders.value(i));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String args[]) {
        addHeaderRequest("http://blog.csdn.net/two_water");
    }
}

我们也可以通过 Fiddler 来查看到我们请求中的请求头的,合理使用这些工具可以验证我们获取的数据是否正确,少走一些弯路

Fiddler查看请求头和响应头

3.添加请求参数的get请求

请求参数的 get 请求,我们使用和风网的免费天气查询 api 作为例子,和风网的官网地址:

http://www.heweather.com/

我们首先的注册一个用户,就会分配key:

和风网免费注册后的个人认证key

注册完成后我们就可以去查找相关的API文档,看看如何调用:

和风网天气api接口

最后就是上代码了:


package com.liangdianshui.http.lib;

import java.io.IOException;

import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * 添加请求参数的get请求
 * <p>
 * Created by Administrator on 2016/11/16 0016.
 */
public class AddQueryParameterRequest {

    /**
     * 使用和风网的免费天气查询的api
     */
    public static void addQueryParameterRequest() {
        OkHttpClient client=new OkHttpClient();
        HttpUrl httpUrl=HttpUrl.parse("https://free-api.heweather.com/v5/now")
                .newBuilder()
                .addQueryParameter("city","shenzhen")
                .addQueryParameter("key"," 9b82700caecd4d3aa709c54a7593754d")
                .build();
        Request request=new Request.Builder().url(httpUrl.toString()).build();
        try {
            Response response=client.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println(response.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
        addQueryParameterRequest();
    }

}


4.post请求
如果使用公共的 api 提交 post 请求,相对于 get 请求来说,是相对麻烦一些的,因此我们自己写一个简单的服务,来请求 post 请求,

服务器的代码主要是这个:


post请求服务器代码

客户端代码:


package com.liangdianshui.http.lib;

import java.io.IOException;

import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * Created by liangdianshui on 2016/11/27 0027.
 */
public class PostRequest {

    public static void postRequest(String url, String name, String password) {
        OkHttpClient client = new OkHttpClient();
        FormBody body = new FormBody.Builder().add("username", name).add("password", password).build();
        Request request = new Request.Builder().url(url).post(body).build();

        try {
            Response reponse = client.newCall(request).execute();
            if (reponse.isSuccessful()) {
                System.out.println(reponse.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
        postRequest("http://localhost:8080/OKHttpTest/OKHttpPost", "liangdianshui", "123456");
    }
}

运行的结果:

post请求结果

在这里呢,我们先了解一个知识点:

POST

可以看到 post 请求中默认的类型就是:application/x-www-form-urlencoded 因此我们可以查看下我们 OKHttp 中的 FormBody 中的源码:

OKHttp源码中FormBody的post请求

可以看到我们使用的 FormBody 就是这个类型的,而 multipart/form-data 这个类型主要是用于上传文件等相关操作的。因为这个上传方式不做编码处理,你上传什么就是什么


5.上传文件

这里我们先写一下服务器的代码,也要了解一下到底 http 是怎样上传文件的

先写一个 html 的页面:

上传文件的页面

然后我们看下服务器的代码,写的非常的简单,主要是我们只是了解下上传文件的流程而已。

上传文件post请求服务器代码

我们来看下效果:

post请求上传文件

好了,服务器完成了,我们来查看一下上传文件的协议是怎样的:

查看协议

可以看到,如果我们自己写上传文件的代码还是比较复杂的,只不过这里面的过程,OKHttp 都帮我们封装好了,因此使用起来还是比较简单的。


package com.liangdianshui.http.lib;

import java.io.File;
import java.io.IOException;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by liangdianshui on 2016/11/28 0028.
 */
public class MultiparHttp {

    public static void main(String args[]) {
        //上传一张本地的图片
        RequestBody imageBody = RequestBody.create(MediaType.parse("image/jpeg"), new File("C:\\Users\\Administrator\\Desktop\\service\\liangdianshui.jpg"));
        MultipartBody body = new MultipartBody.Builder().
                setType(MultipartBody.FORM).  //要配置上传的类型,否则会上传不成功
                addFormDataPart("name", "nate").
                addFormDataPart("filename", "girl.jpg", imageBody).build();
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().
                url("http://localhost:8080/OKHttpTest/UploadServlet").post(body).build();
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println(response.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

运行的结果:


上传图片

6. Http 缓存

其实 OkHttp 给我们封装好了 Http 的缓存,用起来还是挺方便的,可是我们不能仅限于在用,先不说我们要创造属于自己的艺术品,起码我们得知其所以然,只有这样,才能有利于我们技术的进阶。竟然说到 Http 的缓存,那么我们必需得问,为什么要有 Http 请求缓存呢?每个设计肯定有它的思想所在,我们得理解,得探讨。

为什么要有 Http 请求的缓存?
(1): 缓存缓解了网络瓶颈的问题,不需要更多的网络带宽就能更快的加载页面。
(2):缓存减少了冗余的数据传输,节省了网络费用。
(3):缓存降低了对原始服务器的要求,服务器可以更快的响应。同时,搜索引擎的爬虫机器人也能根据过期机制降低爬取的频率,也能有效降低服务器的压力。

当然 Http 请求缓存给我们带来了一系列的好处之外,也有它的不足,那么它有什么不足或缺点呢?
(1)占空间:缓存没有清理机制,这些缓存的文件会永久性地保存在机器上,在特定的时间内,这些文件可能是帮了你大忙,但是时间一长,我们已经不再需要浏览之前的这些网页,这些文件就成了无效或者无用的文件,它们存储在用户硬盘中只会占用空间而没有任何用处,如果要缓存的东西非常多,那就会撑暴整个硬盘空间。
(2)不即现:因为缓存,有时候我们明明修改了样式文件、图片、视频或脚本,刷新页面或部署到站点之后看不到修改之后的效果。所以在产品开发的时候我们总是想办法避免缓存产生,而在产品发布之时又在想策略管理缓存提升网页的访问速度。这就给我们带来了一定的困扰。

那么是怎样实现 Http 的缓存的呢?
其实 Http 缓存在不同的类型上缓存的方式不一样,可是原理还是一样的,我们通过了解浏览器缓存来探讨一下是怎样实现的?

Http缓存

Http 请求缓存中相关的字段有哪些呢?

Http请求缓存缓存相关字段

最后通过请求我的博客来看一下缓存:


请求博客查看缓存

其中:
Cache-control 常见的取值有 private、no-cache、max-age、must-revalidate 等,默认为private 。其作用根据不同的重新浏览方式分为以下几种情况:
(1) 打开新窗口
如果指定 cache-control 的值为 private、no-cache、must-revalidate,那么打开新窗口访问时都会重新访问服务器。而如果指定了 max-age 值,那么在此值内的时间里就不会重新访问服务器,例如:
Cache-control: max-age=5
表示当访问此网页后的5秒内再次访问不会去服务器
(2) 在地址栏回车
如果值为 private 或 must-revalidate(和网上说的不一样),则只有第一次访问时会访问服务器,以后就不再访问。如果值为 no-cache,那么每次都会访问。如果值为 max-age ,则在过期之前不会重复访问。
(3) 按后退按扭
如果值为 private、must-revalidate、max-age,则不会重访问,而如果为 no-cache,则每次都重复访问
(4) 按刷新按扭
无论为何值,都会重复访问

最后我们来看下 OKHttp 是如何设置缓存的:


    /**
     * 请求一个网址,设置缓存
     * <p>要进行缓存,首先网址的服务器端先要支持缓存,再者,我们可以通过
     * @code:{  public Builder cacheControl(CacheControl cacheControl) } 的方式控制客户端的缓存</p>
     *
     * @param url
     * @param file
     * @param maxCacheSize
     * @throws IOException
     */
    public static void cachRequest(String url, File file, int maxCacheSize) throws IOException {
        Cache cache = new Cache(file, maxCacheSize);
        OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
        Request request = new Request.Builder().url(url).build();
        Response response = client.newCall(request).execute();
        String body = response.body().string();
    }

想了解 OKHttp 是如何实现缓存的,我们可以先从 OKHttp 整个的流程图中入手:

OKHttp 流程图

本来还想写完缓存的分析的,可是看了下时间(2016年11月29日01:25:49)已经很晚了,还是睡了,明天还得上班,其实 OKHttp 缓存的实现看了很久源码,里面一大堆的 if 判断,看的有点晕,不过整体大概的原理还是可以理解的,细节的部分就略过了。哎,总是对自己那么仁慈,可能这就是跟大神的距离了。

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,050评论 25 707
  • 参考Android网络请求心路历程Android Http接地气网络请求(HttpURLConnection) 一...
    合肥黑阅读 21,206评论 7 63
  • 1. 点击“设置” 2. 点击“通用” 3. 点击“设备管理” 4. 点击“CITIC”这一条 5. 点击“信任”
    YAO阅读 575评论 1 1
  • 前几天,晚上下班,去市场买菜,然后回家。进屋后,打开音乐。默认播放的列表,有很多歌,现在都不喜欢听了,但有几个人我...
    鱼小哆阅读 1,968评论 0 12