网络加载框架OkHttp

1.什么是OkHttp

github地址:https://square.github.io/okhttp/

由Square公司贡献的一个处理网络请求的开源项目,是目前Android使用最广泛的网络框架。从Android4.4开始
HttpURLConnection的底层实现采用的是OkHttp。

1.支持HTTP/2并允许对同一主机的所有请求共享一个套接字;
2.如果非HTTP/2,则通过连接池,减少了请求延迟;
3.默认请求GZip压缩数据;
4.响应缓存,避免了重复请求的网络;

依赖:
implementation(“com.squareup.okhttp3:okhttp:4.9.0”)

测试(用于测试http请求的服务器):
URL:https://www.httpbin.org/

2.OkHttp基本用法

OkHttpClient okHttpClient = new OkHttpClient();

同步请求:

Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();
                // 准备好请求的Call对象
                Call call = okHttpClient.newCall(request);
                try {
                    Response response = call.execute();
                    Log.i(TAG, "getSync: " + response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
FormBody formBody = new FormBody.Builder()
                        .add("a", "1").add("b", "2").build();
Request request = new Request.Builder().url("https://www.httpbin.org/post")
                        .post(formBody).build();
                // 准备好请求的Call对象
                Call call = okHttpClient.newCall(request);
                try {
                    Response response = call.execute();
                    Log.i(TAG, "postSync: " + response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }

异步请求:

Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2")
                .build();
        // 准备好请求的Call对象
        Call call = okHttpClient.newCall(request);
        //异步请求
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {

            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                if (response.isSuccessful()) {
                    Log.i(TAG, "getAsync: " + response.body().string());
                }
            }
FormBody formBody = new FormBody.Builder()
                .add("a", "1").add("b", "2").build();
        Request request = new Request.Builder().url("https://www.httpbin.org/post")
                .post(formBody).build();
        // 准备好请求的Call对象
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {

            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                Log.i(TAG, "postAsync: " + response.body().string());
            }

3.POST请求

协议规定 POST 提交的数据必须放在请求体中,但协议并没有规定数据必须使用什么编码方式 。而常用的数据编 码方式有:
https://www.runoob.com/http/http-content-type.html

1.Content-Type:application/x-www-form-urlencoded 数据被编码为名称/值对,默认类型;
2.Content-Type:multipart/form-data 数据被编码为一条消息,一般用于文件上传;
3.Content-Type:application/octet-stream 提交二进制数据,如果用于文件上传,只能上传一个文件;
4.Content-Type:application/json 提交json数据

multipart上传文件示例(创建测试代码,上传本地桌面文档):

 @Test
    public void uploadFileTest() throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        File file1 = new File("C:\\Users\\Administrator\\Desktop\\1.txt");
        File file2 = new File("C:\\Users\\Administrator\\Desktop\\2.txt");
        MultipartBody multipartBody = new MultipartBody.Builder()
                .addFormDataPart("file1", file1.getName(), RequestBody.create(file1, MediaType.parse("text/plain")))
                .addFormDataPart("file2", file2.getName(), RequestBody.create(file2, MediaType.parse("text/plain")))
                .addFormDataPart("a", "1")
                .build();
        Request request = new Request.Builder().url("https://www.httpbin.org/post").post(multipartBody).build();
        Call call = okHttpClient.newCall(request);
        Response response = call.execute();
        System.out.println(response.body().string());
    }

json格式上传示例:

```java
 @Test
    public void jsonTest() throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        RequestBody requestBody =
                RequestBody.create("{\"a\":1,\"b\":2}", MediaType.parse("application/json"));
        Request request = new Request.Builder().url("https://www.httpbin.org/post").post(requestBody).build();
        Call call = okHttpClient.newCall(request);
        Response response = call.execute();
        System.out.println(response.body().string());

   }

4.Builder构建者

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

在这里插入图片描述

5.拦截器

概念以及详细使用

OkHttpClientokHttpClient=newOkHttpClient.Builder().addInterceptor(newXXX).build();
OkHttpClientokHttpClient=newOkHttpClient.Builder().addNetworkInterceptor(newXXX).build();

在这里插入图片描述

6.缓存与Cookie

OkHttp按照Http协议规则实现了缓存的处理,缓存是比如:当我们发起第一次请求之后,如果后续还需要进
行同样的请求,此时如果符合缓存规则,则可以减少与服务器的网络通信,直接从本地文件缓存中读取响应
返回给请求者。但是默认情况下,OkHttp的缓存是关闭状态,需要我们开启。

在这里插入图片描述
拦截器以及缓存代码示例:

 @Test
    public void interceptorTest() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .cache(new Cache(new File("C:\\Users\\Administrator\\Desktop"),
                        1024 * 1024)).addNetworkInterceptor(new Interceptor() {
                    @NotNull
                    @Override
                    public Response intercept(@NotNull Chain chain) throws IOException {
                        System.out.println("version:" + chain.request().header("version"));
                        return chain.proceed(chain.request());
                    }
                }).addInterceptor(new Interceptor() {
                    @NotNull
                    @Override
                    public Response intercept(@NotNull Chain chain) throws IOException {
                        //前置处理
                        Request request = chain.request().newBuilder().addHeader("os", "android")
                                .addHeader("version", "1.0").build();
                        Response response = chain.proceed(request);
                        //后置处理
                        return response;
                    }
                }).build();

        Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();
        // 准备好请求的Call对象
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            System.out.println(response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Cookie是某些网站为了辨别用户身份,进行会话跟踪(比如确定登陆状态)而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息
在这里插入图片描述
关于cookie的使用:

public class CookieUnitTest {
    Map<String, List<Cookie>> cookies = new HashMap<>();

    @Test
    public void cookieTest() {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .cookieJar(new CookieJar() {
                    @Override
                    public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {
                        cookies.put(httpUrl.host(), list);
                    }

                    @NotNull
                    @Override
                    public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
                        List<Cookie> cookies = CookieUnitTest.this.cookies.get(httpUrl.host());
                        return cookies == null ? new ArrayList<>() : cookies;
                    }
                })
                .build();
        FormBody formBody = new FormBody.Builder().add("username", "lanceedu")
                .add("password", "123123").build();
        Request request = new Request.Builder().url("https://www.wanandroid.com/user/login")
                .post(formBody).build();
        // 准备好请求的Call对象
        Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            System.out.println(response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }


        request = new Request.Builder().url("https://www.wanandroid.com/lg/collect/list/0/json")
                .build();
        // 准备好请求的Call对象
        call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            System.out.println(response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

返回的数据:

{"data":{"admin":false,"chapterTops":[],"coinCount":2542,"collectIds":[17188,18965,20087,19623],"email":"","icon":"","id":86459,"nickname":"lanceedu","password":"","publicName":"lanceedu","token":"","type":0,"username":"lanceedu"},"errorCode":0,"errorMsg":""}
{"data":{"curPage":1,"datas":[{"author":"xiaoyang","chapterId":440,"chapterName":"官方","courseId":13,"desc":"<p>Gson大家一定不陌生,在很多项目中都大规模使用。</p>\r\n<p>例如常见的:</p>\r\n<pre><code>网络请求\r\n    -&gt;返回Json数据\r\n    -&gt;Gson解析为对象\r\n    -&gt;渲染页面\r\n</code></pre><p>很多时候,历史项目包含很多Gson解析对象在UI线程的操作,或者说即使在子线程其实也会影响页面展现速度。</p>\r\n<p>大家都了解Gson对于对象的解析,如果不单独的配置TypeAdapter,那么其实内部是充满反射的。</p>\r\n<p>问题来了:</p>\r\n<p><strong>有没有什么低侵入的方案可以尽可能去除反射操作,从而提升运行效率?描述思路即可。</strong></p>","envelopePic":"","id":223224,"link":"https://wanandroid.com/wenda/show/19623","niceDate":"2021-10-15 16:52","origin":"","originId":19623,"publishTime":1634287963000,"title":"每日一问 | Gson中序列化对象的操作有低侵入的优化方案吗?","userId":86459,"visible":0,"zan":0},{"author":"xiaoyang","chapterId":360,"chapterName":"小编发布","courseId":13,"desc":"<p>这是一个收集建议、功能的帖子。</p>\r\n<p>如果你有:</p>\r\n<ol>\r\n<li>想要添加的功能;</li>\r\n<li>觉得目前需要改进的地方;</li>\r\n</ol>\r\n<p>欢迎提出,会在评估后安排更新~</p>","envelopePic":"","id":223223,"link":"https://www.wanandroid.com/wenda/show/20087","niceDate":"2021-10-15 16:51","origin":"","originId":20087,"publishTime":1634287899000,"title":"给 wanandroid 提个意见吧!","userId":86459,"visible":0,"zan":0},{"author":"xiaoyang","chapterId":440,"chapterName":"官方","courseId":13,"desc":"<p>关于 Activity 重建,我们探究几个问题:</p>\r\n<ol>\r\n<li>当前 app 正在前台运行,不在栈顶的 Activity 有可能会因为系统资源,例如内存等不足回收吗?</li>\r\n<li>当 app 处于后台运行,app 进程未被杀死,其内部的 Activity 会被回收吗?</li>\r\n<li>当 app 处于后台运行,app 的进程会被杀死吗?</li>\r\n</ol>\r\n<p>如果有能力,建议解释过程中可以配合源码,不一定要全部答出来~</p>","envelopePic":"","id":210658,"link":"https://www.wanandroid.com/wenda/show/18965","niceDate":"2021-08-03 10:43","origin":"","originId":18965,"publishTime":1627958636000,"title":"每日一问 | 关于 Activity 重建,值得探究的几个问题","userId":86459,"visible":0,"zan":0},{"author":"","chapterId":502,"chapterName":"自助","courseId":13,"desc":"","envelopePic":"","id":173169,"link":"https://mp.weixin.qq.com/s/N4e6AkhNgI3mcbWFlqhYPQ","niceDate":"2021-02-05 17:22","origin":"","originId":17188,"publishTime":1612516968000,"title":"Gradle系列之初识Gradle篇","userId":86459,"visible":0,"zan":0}],"offset":0,"over":true,"pageCount":1,"size":20,"total":4},"errorCode":0,"errorMsg":""}

PS:这里使用的是玩安卓的API(只有保持登录状态后才能访问收藏的文章):https://www.wanandroid.com/blog/show/2

在这里插入图片描述
在这里插入图片描述
关于cookie的现状:链接

本文demo:https://github.com/gujunhe/NetworkDemo.git

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gujunhe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值