Download OkHttp3

implementation 'com.squareup.okhttp3:okhttp:3.10.0'

1.1. 异步GET请求

-new OkHttpClient;

-构造Request对象;

-通过前两步中的对象构建Call对象;

-通过Call#enqueue(Callback)方法来提交异步请求;

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.get()//默认就是GET请求,可以不写
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
} @Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});

异步发起的请求会被加入到 Dispatcher 中的 runningAsyncCalls双端队列中通过线程池来执行。

1.2. 同步GET请求

前面几个步骤和异步方式一样,只是最后一部是通过 Call#execute() 来提交请求,注意这种方式会阻塞调用线程,所以在Android中应放在子线程中执行,否则有可能引起ANR异常,Android3.0 以后已经不允许在主线程访问网络。

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.build();
final Call call = okHttpClient.newCall(request);
new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = call.execute();
Log.d(TAG, "run: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();

2.1. POST方式提交String

这种方式与前面的区别就是在构造Request对象时,需要多构造一个RequestBody对象,用它来携带我们要提交的数据。在构造 RequestBody 需要指定MediaType,用于描述请求/响应 body 的内容类型,关于 MediaType 的更多信息可以查看 RFC 2045

request_body

MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
String requestBody = "I am Jdqm.";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(mediaType, requestBody))
.build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
} @Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});

响应内容

http/1.1 200 OK
Date:Sat, 10 Mar 2018 05:23:20 GMT
Content-Type:text/html;charset=utf-8
Content-Length:18
Server:GitHub.com
Status:200 OK
X-RateLimit-Limit:60
X-RateLimit-Remaining:52
X-RateLimit-Reset:1520661052
X-CommonMarker-Version:0.17.4
Access-Control-Expose-Headers:ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval Access-Control-Allow-Origin:*
Content-Security-Policy:default-src 'none'
Strict-Transport-Security:max-age=31536000; includeSubdomains; preload
X-Content-Type-Options:nosniff
X-Frame-Options:deny
X-XSS-Protection:1; mode=block
X-Runtime-rack:0.019668
Vary:Accept-Encoding
X-GitHub-Request-Id:1474:20A83:5CC0B6:7A7C1B:5AA36BC8
onResponse: <p>I am Jdqm.</p>

2.2 POST方式提交流

RequestBody requestBody = new RequestBody() {
@Nullable
@Override
public MediaType contentType() {
return MediaType.parse("text/x-markdown; charset=utf-8");
} @Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("I am Jdqm.");
}
}; Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
} @Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});

2.3. POST提交文件

MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
OkHttpClient okHttpClient = new OkHttpClient();
File file = new File("test.md");
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(mediaType, file))
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
} @Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});

2.4. POST方式提交表单

OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("search", "Jurassic Park")
.build();
Request request = new Request.Builder()
.url("https://en.wikipedia.org/w/index.php")
.post(requestBody)
.build(); okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
} @Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});

提交表单时,使用 RequestBody 的实现类FormBody来描述请求体,它可以携带一些经过编码的 key-value 请求体,键值对存储在下面两个集合中:

  private final List<String> encodedNames;
private final List<String> encodedValues;

2.5. POST方式提交分块请求

MultipartBody 可以构建复杂的请求体,与HTML文件上传形式兼容。多块请求体中每块请求都是一个请求体,可以定义自己的请求头。这些请求头可以用来描述这块请求,例如它的 Content-Disposition 。如果 Content-LengthContent-Type 可用的话,他们会被自动添加到请求头中。

private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png"); private void postMultipartBody() {
OkHttpClient client = new OkHttpClient(); // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
MultipartBody body = new MultipartBody.Builder("AaB03x")
.setType(MultipartBody.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "Square Logo"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"image\""),
RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
.build(); Request request = new Request.Builder()
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.url("https://api.imgur.com/3/image")
.post(body)
.build(); Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) { } @Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string()); } });
}

3.拦截器-interceptor

OkHttp的拦截器链可谓是其整个框架的精髓,用户可传入的 interceptor 分为两类:

①一类是全局的 interceptor,该类 interceptor 在整个拦截器链中最早被调用,通过 OkHttpClient.Builder#addInterceptor(Interceptor) 传入;

②另外一类是非网页请求的 interceptor ,这类拦截器只会在非网页请求中被调用,并且是在组装完请求之后,真正发起网络请求前被调用,所有的 interceptor 被保存在 List<Interceptor> interceptors 集合中,按照添加顺序来逐个调用,具体可参考 RealCall#getResponseWithInterceptorChain() 方法。通过 OkHttpClient.Builder#addNetworkInterceptor(Interceptor) 传入;

这里举一个简单的例子,例如有这样一个需求,我要监控App通过 OkHttp 发出的所有原始请求,以及整个请求所耗费的时间,针对这样的需求就可以使用第一类全局的 interceptor 在拦截器链头去做。

OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
Request request = new Request.Builder()
.url("http://www.publicobject.com/helloworld.txt")
.header("User-Agent", "OkHttp Example")
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
} @Override
public void onResponse(Call call, Response response) throws IOException {
ResponseBody body = response.body();
if (body != null) {
Log.d(TAG, "onResponse: " + response.body().string());
body.close();
}
}
});
public class LoggingInterceptor implements Interceptor {
private static final String TAG = "LoggingInterceptor"; @Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request(); long startTime = System.nanoTime();
Log.d(TAG, String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers())); Response response = chain.proceed(request); long endTime = System.nanoTime();
Log.d(TAG, String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (endTime - startTime) / 1e6d, response.headers())); return response;
}
}

针对这个请求,打印出来的结果

Sending request http://www.publicobject.com/helloworld.txt on null
User-Agent: OkHttp Example Received response for https://publicobject.com/helloworld.txt in 1265.9ms
Server: nginx/1.10.0 (Ubuntu)
Date: Wed, 28 Mar 2018 08:19:48 GMT
Content-Type: text/plain
Content-Length: 1759
Last-Modified: Tue, 27 May 2014 02:35:47 GMT
Connection: keep-alive
ETag: "5383fa03-6df"
Accept-Ranges: bytes

注意到一点是这个请求做了重定向,原始的 request urlhttp://www.publicobject.com/helloworld.tx,而响应的 request urlhttps://publicobject.com/helloworld.txt,这说明一定发生了重定向,但是做了几次重定向其实我们这里是不知道的,要知道这些的话,可以使用 addNetworkInterceptor()去做。更多的关于 interceptor的使用以及它们各自的优缺点,请移步OkHttp官方说明文档

4.其他

  1. 推荐让 OkHttpClient 保持单例,用同一个 OkHttpClient 实例来执行你的所有请求,因为每一个 OkHttpClient 实例都拥有自己的连接池和线程池,重用这些资源可以减少延时和节省资源,如果为每个请求创建一个 OkHttpClient 实例,显然就是一种资源的浪费。当然,也可以使用如下的方式来创建一个新的 OkHttpClient 实例,它们共享连接池、线程池和配置信息。
    OkHttpClient eagerClient = client.newBuilder()
.readTimeout(500, TimeUnit.MILLISECONDS)
.build();
Response response = eagerClient.newCall(request).execute();
  1. 每一个Call(其实现是RealCall)只能执行一次,否则会报异常,具体参见 RealCall#execute()

相关阅读

OkHttp的使用的更多相关文章

  1. Android okHttp网络请求之Json解析

    前言: 前面两篇文章介绍了基于okHttp的post.get请求,以及文件的上传下载,今天主要介绍一下如何和Json解析一起使用?如何才能提高开发效率? okHttp相关文章地址: Android o ...

  2. okhttp封装时,提示 cannot resolve method OkHttpClient setConnectTimeout() 函数

    如标题所示,okhttp封装时,提示 cannot resolve method  OkHttpClient setConnectTimeout() 函数,有遇到这样现象的朋友吗? 原因:因使用的是 ...

  3. RxAndroid+Retrofit+MVVM(1)OKHttp

    1)Gradlecompile 'com.squareup.okhttp:okhttp:2.4.0'compile 'com.squareup.okio:okio:1.5.0' 2)Get //创建o ...

  4. Android okHttp网络请求之Get/Post请求

    前言: 之前项目中一直使用的Xutils开源框架,从xutils 2.1.5版本使用到最近的xutils 3.0,使用起来也是蛮方便的,只不过最近想着完善一下app中使用的开源框架,由于Xutils里 ...

  5. Android okHttp网络请求之文件上传下载

    前言: 前面介绍了基于okHttp的get.post基本使用(http://www.cnblogs.com/whoislcj/p/5526431.html),今天来实现一下基于okHttp的文件上传. ...

  6. Android okHttp网络请求之缓存控制Cache-Control

    前言: 前面的学习基本上已经可以完成开发需求了,但是在项目中有时会遇到对请求做个缓存,当没网络的时候优先加载本地缓存,基于这个需求我们来学习一直okHttp的Cache-Control. okHttp ...

  7. Android okHttp网络请求之Retrofit+Okhttp+RxJava组合

    前言: 通过上面的学习,我们不难发现单纯使用okHttp来作为网络库还是多多少少有那么一点点不太方便,而且还需自己来管理接口,对于接口的使用的是哪种请求方式也不能一目了然,出于这个目的接下来学习一下R ...

  8. 安卓学习----使用okHttp(get方式)---下载图片

    一首先下载Jar包 https://github.com/square/okhttp 如果使用android studio只需要加入依赖 compile 'com.squareup.okhttp3:o ...

  9. Android 框架学习之 第一天 okhttp & Retrofit

    最近面试,一直被问道新技术新框架,这块是短板,慢慢补吧. 关于框架的学习,分几个步骤 I.框架的使用 II.框架主流使用的版本和Android对应的版本 III.框架的衍生使用比如okhttp就会有R ...

  10. OkHttp简介

    什么是OKHttp 一般在Java平台上,我们会使用Apache HttpClient作为Http客户端,用于发送 HTTP 请求,并对响应进行处理.比如可以使用http客户端与第三方服务(如SSO服 ...

随机推荐

  1. ES6 的基础教程

    一.介绍 1.历史 ECMAScript和JavaScript ECMA是标准,JS是实现 类似于HTML5是标准,IE10.Chrome.FF都是实现 换句话说,将来也能有其他XXXScript来实 ...

  2. 初学Java if选择语句

    import java.util.Scanner; public class SubtractionQuiz { public static void main(String[] agrs) { ); ...

  3. PL SQL安装

    首先,在官网下载PL SQL 的对应版本,本机是64位的就下载64位的,网址:https://www.allroundautomations.com/downloads.html#PLS 点击应用程序 ...

  4. HTML5 表单提交实例

    html <!DOCTYPE html> <html> <head> <title>表单</title> <meta charset= ...

  5. Java中的heap和stack

    heap和stack Java的内存分为两类,一类是栈内存,一类是堆内存. 栈内存:是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配 ...

  6. RabbitMQ:伪延时队列

    目录 一.什么是延时队列 二.RabbitMQ实现 三. 延时队列的问题 四.解决RabbitMQ的伪延时方案 ps:伪延时队列先卖个关子,我们先了解下延时队列. 一.什么是延时队列 所谓延时队列是指 ...

  7. Python格式输出汇总

    print ('%10s'%('test')) print ('{:<10}'.format('test'))#left-aligned print ('{:>10}'.format('t ...

  8. 2019牛客多校第六场 B - Shorten IPv6 Address 模拟

    B - Shorten IPv6 Address 题意 给你\(128\)位的二进制,转换为十六进制. 每\(4\)位十六进制分为\(1\)组,每两组用一个\(":"\)分开. 每 ...

  9. 禁止多用户进入win7系统的方法(图文)

    windows7系统可以支持多用户登陆,虽然它能为使用者提供方便,但是为安全起见,一些用户想要禁止多用户进入win7系统,因为我们并不能保证其他账户用户在使用过程中是否会安装病毒程序.那么如何禁止多用 ...

  10. [NOIP模拟20]题解

    来自达哥的问候…… A.周 究级难题,完全不可做QAQ #include<cstdio> #include<iostream> #include<cstring> ...