之前说到OKHttp网络请求支持两种方式:同步请求和异步请求,同时又存在get和post请求,那么就是2*2,一共四种情况,接下来就分别介绍下这四种请求的使用和区别

在gradle中指定Java版本

compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8
}

说到这里,需要补一点,关于Android 9.0的http限制:默认使用加密连接,Android P禁止 App 使用所有未加密的连接,因此 Android P 系统无论是接收或者发送流量,都不能明码传输,需要使用下一代(Transport Layer Security)传输层安全协议,如果在Android P中使用http地址,将会出现如下错误(这里使用的url为http://www.baidu.com
W/System.err: java.net.UnknownServiceException: CLEARTEXT communication to www.baidu.com not permitted by network security policy
为了解决这个问题,常见的处理方式有三种:

  • APP改用https请求
  • targetSdkVersion 降到27(Android 8.1)以下
  • 在 res 下新增一个 xml 目录,然后创建配置文件。再在application中添加进来
<?xml version="1.0" encoding="utf-8"?>
<network-security-config><base-config cleartextTrafficPermitted="true" />
</network-security-config>
android:networkSecurityConfig="@xml/network_security_config"

同步请求

  • get同步请求
private void synGetRequest() {new Thread(new Runnable() {@Overridepublic void run() {OkHttpClient mClient = new OkHttpClient.Builder().callTimeout(5, TimeUnit.SECONDS) //设置超时时间.build(); //构建OkHttpClient对象Request request = new Request.Builder().url("http://www.baidu.com") //请求url.get() //默认请求方式,写不写都是get.build(); //创建Request对象Call call = mClient.newCall(request); //构建Call对象try {Response response = call.execute(); //得到Response对象if(response.isSuccessful()) {Log.e(TAG, "response code ==> " + response.code());Log.e(TAG, "response message ==> " + response.message());Log.e(TAG, "response res ==> " + response.body().string());}else {Log.e(TAG, "response fail");}} catch (IOException e) {e.printStackTrace();}}}).start();
}

此时得到的log如下(省略了html的一长串内容):

D/NetworkSecurityConfig: Using Network Security Config from resource network_security_config debugBuild: true
E/MainActivity: response code ==> 200
E/MainActivity: response message ==> OK
E/MainActivity: response res ==> <!DOCTYPE html><!--STATUS OK--><html> ··· </html>

使用注意:
由于同步请求是阻塞线程的(call.execute()),所以在使用的时候需要在子线程中运行,同时response.body().string()其本质上是对流的操作,也是需要在子线程中进行。另外,返回码中的code是在http中定义的,遵行http协议。由于response.body().string()的本质是对流进行操作,所以,在调用的时候,只会得到一次的返回值,再次调用会返回null,其根本原因是客户端发出请求,服务端做出响应,将数据写入到流中,客户端得到返回值,再次调用时服务端并没有在流中写入数据,此时客户端就没有数据,得到的就为null。

  • post同步请求
private void synPostRequest() {new Thread(new Runnable() {@Overridepublic void run() {OkHttpClient mClient = new OkHttpClient.Builder().callTimeout(5, TimeUnit.SECONDS) //设置超时时间.build(); //构建OkHttpClient对象MediaType JSON = MediaType.parse("application/json; charset=utf-8"); //数据类型为json格式,String json = "{\"username\":\"chen\"}"; //json数据RequestBody body = RequestBody.create(JSON, json); //创建RequestBody对象Request request = new Request.Builder().url("http://www.baidu.com") //请求url.post(body) //post请求方式,需要传入RequestBody对象.build(); //创建Request对象Call call = mClient.newCall(request); //构建Call对象try {Response response = call.execute(); //得到Response对象if (response.isSuccessful()) {Log.e(TAG, "response code ==> " + response.code());Log.e(TAG, "response message ==> " + response.message());Log.e(TAG, "response res ==> " + response.body().string());} else {Log.e(TAG, "response fail");}} catch (IOException e) {e.printStackTrace();}}}).start();
}

post与get同步请求的区别在与post是需要带入请求体的,这也和get与post请求的本质区别有关。
post需要构建出请求体,从而完成post请求。

同步请求方法总结:

  1. 创建OkHttpClientRequest对象
  2. Request封装成Call对象
  3. 调用Callexecute()方法发送同步请求

异步请求

  • get异步请求
private void asyGetRequest() {OkHttpClient mClient = new OkHttpClient.Builder().callTimeout(5, TimeUnit.SECONDS) //设置超时时间.build(); //构建OkHttpClient对象Request request = new Request.Builder().url("https://www.baidu.com").get().build();Call call = mClient.newCall(request);call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) { //请求失败回调Log.e(TAG, "onFailure ===> " + e.getMessage());}@Overridepublic void onResponse(Call call, Response response) throws IOException { //请求成功回调Log.e(TAG, "onResponse ===> " + response.body().string());}});
}

使用注意:
回调接口位于子线程,即call.enqueue()会将网络请求放在子线程中执行,说到这,就该知道UI更新什么的该怎么使用了吧。

  • post异步请求
    嗯~~~,这个和上面的get异步请求差不多,区别在于post请求需要构建RequestBody对象传入post(),从而完成Request对象的构建,其他也就没啥区别了。

异步请求方法总结:

  1. 创建OkHttpClientRequest对象
  2. Request封装成Call对象
  3. 调用Callenqueue()方法进行异步请求
  • post参数说明
    查看post的方法
public Builder post(RequestBody body) {return method("POST", body);
}

可以看到传入的参数为:RequestBody,那么这是个什么玩意儿呢?
其实就是请求体,再看看怎么构建,查看源代码会发现有五种静态构建方法

RequestBody.create(MediaType, String)
RequestBody.create(MediaType, ByteString)
RequestBody.create(MediaType, byte[])
RequestBody.create(MediaType, byte[], int, int)
RequestBody.create(MediaType, File)

其源代码如下

public abstract class RequestBody {···/*** Returns a new request body that transmits {@code content}. If {@code contentType} is non-null* and lacks a charset, this will use UTF-8.*/public static RequestBody create(@Nullable MediaType contentType, String content) {Charset charset = UTF_8;if (contentType != null) {charset = contentType.charset();if (charset == null) {charset = UTF_8;contentType = MediaType.parse(contentType + "; charset=utf-8");}}byte[] bytes = content.getBytes(charset);return create(contentType, bytes);}/** Returns a new request body that transmits {@code content}. */public static RequestBody create(final @Nullable MediaType contentType, final ByteString content) {return new RequestBody() {@Override public @Nullable MediaType contentType() {return contentType;}@Override public long contentLength() throws IOException {return content.size();}@Override public void writeTo(BufferedSink sink) throws IOException {sink.write(content);}};}/** Returns a new request body that transmits {@code content}. */public static RequestBody create(final @Nullable MediaType contentType, final byte[] content) {return create(contentType, content, 0, content.length);}/** Returns a new request body that transmits {@code content}. */public static RequestBody create(final @Nullable MediaType contentType, final byte[] content,final int offset, final int byteCount) {if (content == null) throw new NullPointerException("content == null");Util.checkOffsetAndCount(content.length, offset, byteCount);return new RequestBody() {@Override public @Nullable MediaType contentType() {return contentType;}@Override public long contentLength() {return byteCount;}@Override public void writeTo(BufferedSink sink) throws IOException {sink.write(content, offset, byteCount);}};}/** Returns a new request body that transmits the content of {@code file}. */public static RequestBody create(final @Nullable MediaType contentType, final File file) {if (file == null) throw new NullPointerException("file == null");return new RequestBody() {@Override public @Nullable MediaType contentType() {return contentType;}@Override public long contentLength() {return file.length();}@Override public void writeTo(BufferedSink sink) throws IOException {try (Source source = Okio.source(file)) {sink.writeAll(source);}}};}
}

常用的RequestBody有json与file,那么具体怎么构建呢,以下举出两个例子
JSON格式上传

MediaType JSON = MediaType.parse("application/json; charset=utf-8"); //数据类型为json格式
String json = "{\"username\":\"chen\"}";
RequestBody body = RequestBody.create(JSON, json);

FILE格式上传

MediaType fileType = MediaType.parse("File/*"); //数据类型为file格式
File file = new File("/sdcard/test.txt");
RequestBody body = RequestBody.create(fileType, file);

同时查看源代码还发现,RequestBody有两个实现类,FormBodyMultipartBody,这两个是OkHttp对RequestBody的实现,前者用于传递键值对参数,后者用于传递复杂参数。
例如使用FormBody传递键值对

RequestBody body = new FormBody.Builder() //创建表单请求.add("username","chen").add("from","PC").build();

使用MultipartBody的例子

MultipartBody multipartBody = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("title", "title") //键值对.addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("file/*"), file)) //文件.build();

这里需要说明一点,OkHttp并没有实现文件的下载功能,但我们可以拿到流,那么也就是说可以将流转化为文件保存,也就实现了文件下载功能。

热门开源项目源代码分析导航

OkHttp从使用到源代码分析(2)-请求的使用方法相关推荐

  1. struts2请求过程源代码分析

    struts2请求过程源代码分析 Struts2是Struts社区和WebWork社区的共同成果.我们甚至能够说,Struts2是WebWork的升级版.他採用的正是WebWork的核心,所以.Str ...

  2. BT源代码学习心得(八):跟踪服务器(Tracker)的代码分析(用户请求的实际处理) - 转贴自 wolfenstein (NeverSayNever)

    BT源代码学习心得(八):跟踪服务器(Tracker)的代码分析(用户请求的实际处理) author: wolfenstein 通过上一次的分析,我们已经知道了Tracker采用http协议和客户端通 ...

  3. Android应用程序进程启动过程的源代码分析(1)

    Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信机制:这两个特点都是在进程的初始化过程中实 ...

  4. AFNetworking 源代码分析

    关于其他 AFNetworking 源代码分析的其他文章: AFNetworking 概述(一) AFNetworking 的核心 AFURLSessionManager(二) 处理请求和响应 AFU ...

  5. 区块链教程Fabric1.0源代码分析scc(系统链码)

    区块链教程Fabric1.0源代码分析scc(系统链码),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初期泡沫的渐退,让人们更 ...

  6. HBase源代码分析之MemStore的flush发起时机、推断条件等详情(二)

    在<HBase源代码分析之MemStore的flush发起时机.推断条件等详情>一文中,我们具体介绍了MemStore flush的发起时机.推断条件等详情.主要是两类操作.一是会引起Me ...

  7. CASSINI源代码分析

    CASSINI源代码分析 2004-11-10 http://blog.csdn.net/shanhe/ 为什么要分析CASSINI? Cassini(卡西尼)是asp.net上的一个开源项目.主要给 ...

  8. KVM虚拟机源代码分析

    1,KVM结构及工作原理 1.1  KVM结构 KVM基本结构有两部分组成.一个是KVM Driver ,已经成为Linux 内核的一个模块.负责虚拟机的创建,虚拟内存的分配,虚拟CPU寄存器的读写以 ...

  9. MyBatis架构设计及源代码分析系列(一):MyBatis架构

    一.概述 MyBatis并不是一个完整的ORM框架,其官方首页是这么介绍自己 The MyBatis data mapper framework makes it easier to use a re ...

最新文章

  1. oracle pl/sql 程序设计 历史笔记整理
  2. html5游戏指尖跟随,图片跟随手指滑动
  3. 深度学习实践:计算机视觉_深度学习与传统计算机视觉技术:您应该选择哪个?
  4. drive es 软件兼容_某知名软件被完美修改!对不住了!
  5. OpenResty+Lua+redis+mysql实现高性能高可用限流缓存
  6. Linux下的iscsi(设备的共享服务)
  7. 深度神经网络基本问题的原理详细分析和推导
  8. scala type关键字用于起别名
  9. docker 容器中设置 mysql lampp php软链接
  10. flashcs3java_Flash CS3组件开发图文教程
  11. 技术人 | 浅谈如何成为技术一号位?
  12. MAX6299MTT在CPLD上的应用
  13. OpenGL ES EGL eglDestroyContext
  14. 英语笔记(计算机词汇,翻译/写作)
  15. C++对于文件的操作(4)——更改文件指定位置的数据(在新旧数据长度不一致的情况下)
  16. 9495 删除线性表中所有值为x的元素
  17. tensorflow与python交互系列,tf.py_function()、tf.py_func、tf.numpy_function()(一)
  18. 866数据结构重点内容
  19. 计算机联锁 组合布置图,车站计算机联锁论文
  20. Monty Python(蒙提·派森)的成员简介

热门文章

  1. 在2K系统下装98的两种方法
  2. 思科模拟器-使用三层交换机实现vlan间的通信
  3. 【深度学习】Ubuntu增加Swap交换空间大小
  4. pc项目,通过左侧导航树展示右侧router
  5. Spring Boot 操作 Redis教程
  6. 华南虎事件续篇之二:周正龙已被警方带走 行踪成谜
  7. vue预览doc,docx,xlsx,pdf等文件方法
  8. 2022年1月27日
  9. Matlab实用教程04:cell2mat函数的使用
  10. 大数据处理神器Beam