每天学习一个Android中的常用框架——3.OkHttp

赈川 2020-11-13 03:45:59
Android 学习 一个 常用 每天


1.简介

在过去,Android上发送HTTP请求一般有两种方式:HttpURLConnection和HttpClient(Apache HttpClient)。不过由于HttpClient存在API数量过多、扩展困难等缺点,Android团队越来越不建议我们使用这种方式。终于在Android 6.0系统中,HttpClient的功能被完全移除了,标志着此功能被正式弃用。虽然官方推荐使用HttpURLConnection,但是在代码编写的过程中仍然会比较繁琐。此时,一个将要替代它们的网络层框架出现了:也就是Okhttp,该框架也是我在《Android 第一行代码》上学到的仅此于Litepal之后的第二个框架。今天重新学习了一下Okhttp,将学习历程记录到博客上,望对读者有帮助。
OkHttp是由鼎鼎大名的Square公司开发的,这个公司在开源事业上面贡献良多,除了 OkHttp 之外,还开发了像Picasso,Retrofit等著名的开源项目。OkHttp不仅在接口封装上面做得简单易用,就连在底层实现上也是自成一派,比起原生的HttpURLConnection,可以说是有过之而无不及,现在已经成了广大Android开发者首选的网络通信库。

2.特性

OkHttp是一个高效的HTTP客户端,它有以下默认特性:

  • 支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
  • 连接池减少请求延时
  • 透明的GZIP压缩减少响应数据的大小
  • 缓存响应内容,避免一些完全重复的请求

当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接,当握手失败时会回退到TLS 1.0。

OkHttp 支持 Android 2.3 及以上版本Android平台, 以及 Java,JDK 1.7及以上.

OkHttp的使用是非常简单的. 它的请求/响应 API 使用构造器模式builders来设计,它支持阻塞式的同步请求和带回调的异步请求
为了更好地演示OkHttp,这里仅展示出同步/异步执行get/post请求的相关api,至于关于OkHttp的相关调用,建议参考OkHttp的官方文档:OkHttp官网,无需翻墙
关于使用post请求发送流/文件/表单等,这些功能则要配合另一个框架:OkIo,将在下一篇博客中专门展示出来。
话不多说,让我们马上开始使用OkHttp吧。

3.演示

3.1 集成

又到了喜闻乐见的集成环节,我们只需要修改module下的build.gradle,加入OkHttp的依赖,代码如下:

implementation("com.squareup.okhttp3:okhttp:4.6.0")

记得重新Sync一下,确保OkHttp集成到了你的项目中。作者在写下此篇博客时OkHttp3的稳定版本号以达到4.6.0,如果读者在OkHttp的官网上发现了更新的版本,记得及时更新,做到与时俱进。

3.2 配置

既然你集成了OkHttp,就不可不免地要进行与网络有关的操作。既然如此,就需要在清单文件下声明网络权限,即:

<uses-permission android:name="android.permission.INTERNET" />

另外:如果你的Android版本为Android P(即targetSdkVersion 27),在运行该项目时可能会报有关网络的错误,如图所示:
在这里插入图片描述
原因:在Android P系统的设备上,如果应用使用的是非加密的明文流量的http网络请求,则会导致该应用无法进行网络请求,https则不会受影响,同理若应用内使用WebView加载网页 则加载网页也需要是https请求。
解决方法

  • APP整体网络请求改用https
  • 将targetSdkVersion 版本下调至27以下
  • 更改项目网络安全配置

三种方法亦可,这里主要介绍一下第三种解决方法,以拓宽解决思路

  1. 在res目录下新建xml文件夹 在xml文件夹内新建名为network_config(名字非固定)的xml,代码如下:
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
  1. 然后,在AndroidManifest中增加android:networkSecurityConfig属性,代码如下:
 <application
...
android:networkSecurityConfig="@xml/network_security_config"
...
/>
  1. 以上两个步骤就完成了网络安全配置,如果实在不行的话可以尝试另外两种方法或者百度

3.3 布局文件和URL封装

接下来,我们直接开始布局文件activity_main.xml的编写。该布局很简单,仅有四个按钮,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<Button
android:id="@+id/btn_get_syn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="发送get请求——同步"/>
<Button
android:id="@+id/btn_get_asy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="发送get请求——异步"/>
<Button
android:id="@+id/btn_post_syn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="发送post请求——异步"/>
<Button
android:id="@+id/btn_post_asy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="发送post请求——异步"/>
</LinearLayout>

之后,我们简单用字符串封装一下要请求的URL,即http://wwww.baidu.com。这里建议想要深入OkHttp的读者自己搭建一个Tomcat/Apache服务器,将资源文件上传到服务器上,然后访问一下本地路径,这样可以加深对于网络请求的理解。这里为了便于演示就直接网络请求百度,代码如下:

private static final String URL = "http://wwww.baidu.com";

3.4 同步GET请求

同步GET请求的步骤很简单,大抵分为:

  • 构造OkHttpClient对象;
  • 构造Request对象;
  • 通过前两步中的对象构建Call对象;
  • 通过call.execute()方法来提交同步请求。注意,由于是同步请求,所以该api要放在子线程中,避免阻塞主线程,造成ANR异常。另外,Android3.0 以后已经不允许在主线程访问网络。

代码如下:

private void getBySynchronized() {

btn_get_syn.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {

// 1.构建Client对象
OkHttpClient client = new OkHttpClient();
// 2.采用建造者模式和链式调用构建Request对象
final Request request = new Request.Builder()
.url(URL) // 请求URL
.get() // 默认就是get请求,可以不写
.build();
// 3.通过1和2产生的Client和Request对象生成Call对象
final Call call = client.newCall(request);
// 4.同步发送get请求需要使用execute()方法,并且为了防止主线程阻塞需要放在子线程中自行
new Thread(new Runnable() {

@Override
public void run() {

try {

// 6.构建response对象
Response response = call.execute();
Log.d(TAG, "同步发送get请求成功!请求到的信息为:" + response.body().string());
} catch (IOException e) {

e.printStackTrace();
}
}
}).start();
}
});
}

在这里插入图片描述

3.5 异步GET请求

异步GET请求的前面几个步骤和同步方式一样,只是最后一部是通过call.enqueue(Callback()) 来提交请求,代码如下:

private void getByAsynchronized() {

btn_get_asy.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {

// 1.构建Client对象
OkHttpClient client = new OkHttpClient();
// 2.采用建造者模式和链式调用构建Request对象
final Request request = new Request.Builder()
.url(URL) // 请求URL
.get() // 默认就是get请求,可以不写
.build();
// 3.通过1和2产生的Client和Request对象生成Call对象
Call call = client.newCall(request);
// 4.调用Call对象的enqueue()方法,并且实现一个回调实现类
call.enqueue(new Callback() {

@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {

Log.d(TAG, "异步发送get请求失败!");
e.printStackTrace();
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {

Log.d(TAG, "异步发送get请求成功!请求到的信息为:" + response.body().string());
}
});
}
});
}

在这里插入图片描述

3.6 同步POST请求

同步POST请求的步骤类似于同步GET请求,大抵分为:

  • 构造OkHttpClient对象;
  • 构造FormBody对象(键值对)
  • 构造Request对象;
  • 通过前两步中的对象构建Call对象;
  • 通过call.execute()方法来提交同步请求。

代码如下:

private void postBySynchronized() {

btn_post_syn.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {

// 1.构建Client对象
OkHttpClient client = new OkHttpClient();
// 2.采用建造者模式和链式调用构建键值对对象
FormBody formBody = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build();
// 3.采用建造者模式和链式调用构建Request对象
final Request request = new Request.Builder()
.url(URL) // 请求URL
.post(formBody) // 默认就是get请求,可以不写
.build();
// 4.通过1和3产生的Client和Request对象生成Call对象
final Call call = client.newCall(request);
// 5.同步发送post请求需要使用execute()方法,并且为了防止主线程阻塞需要放在子线程中自行
new Thread(new Runnable() {

@Override
public void run() {

try {

// 6.构建response对象
Response response = call.execute();
Log.d(TAG, "同步发送post请求成功!请求到的信息为:" + response.body().string());
} catch (IOException e) {

e.printStackTrace();
}
}
}).start();
}
});
}

在这里插入图片描述

3.7 异步POST请求

异步POST请求的前面几个步骤和同步方式一样,只是最后一部是通过call.enqueue(Callback()) 来提交请求,代码如下:

private void postByAsynchronized() {

btn_post_asy.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {

// 1.构建Client对象
OkHttpClient client = new OkHttpClient();
// 2.采用建造者模式和链式调用构建键值对对象
FormBody formBody = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build();
// 3.采用建造者模式和链式调用构建Request对象
final Request request = new Request.Builder()
.url(URL) // 请求URL
.post(formBody) // 默认就是get请求,可以不写
.build();
// 4.通过1和3产生的Client和Request对象生成Call对象
Call call = client.newCall(request);
// 5.调用Call对象的enqueue()方法,并且实现一个回调实现类
call.enqueue(new Callback() {

@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {

Log.d(TAG, "异步发送post请求失败!");
e.printStackTrace();
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {

Log.d(TAG, "异步发送post请求成功!请求到的信息为:" + response.body().string());
}
});
}
});
}

在这里插入图片描述

4 总结

  • 同步调用:编写简单,但是会阻塞主线程,一般不适用
  • 异步调用:回调函数是在子线程,我们不能在子线程更新UI,需要借助于runOnUiThread()方法或者Handler来处理

一般来说,虽说同步/异步调用各有优劣,在实际项目里,我们还是异步调用会相对用得多一些,搭配RxJava/RxAndroid以及EventBus,可以提升用户的体验。当然,如果是为了快速开发比较简单的小demo,同步调用也够用了。

5.源码地址

AFL——Android框架学习

版权声明
本文为[赈川]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_41151659/article/details/105935339

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple