OkHttp使用教程
Android系统提供了两种HTTP通信类,HttpURLConnection和HttpClient。
关于HttpURLConnection和HttpClient的选择>>官方博客
尽管Google在大部分安卓版本中推荐使用HttpURLConnection,但是这个类相比HttpClient实在是太难用,太弱爆了。
OkHttp是一个相对成熟的解决方案,据说Android4.4的源码中可以看到HttpURLConnection已经替换成OkHttp实现了。所以我们更有理由相信OkHttp的强大。
OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。
使用 OkHttp 无需重写您程序中的网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的API。如果你用了 Apache HttpClient,则OkHttp也提供了一个对应的okhttp-apache 模块。
注:在国内使用OkHttp会因为这个问题导致部分酷派手机用户无法联网,所以对于大众app来说,需要等待这个bug修复后再使用。或者尝试使用OkHttp的老版本。
截止到目前,OkHttp一直没有修复,并把修复计划延迟到了OkHttp2.3中。不是所有设备都能重现,仅少量设备会出现这个问题。(如果问题这么明显,OkHttp早就修复了)
入门
官方资料
使用范围
OkHttp支持Android 2.3及其以上版本。
对于Java, JDK1.7以上。
jar包准备
官方介绍页面有链接位置。这里把下载链接也写在下面。
OkHttp
Okio
基本使用
HTTP GET
1
2
3
4
5
6
7
8
|
OkHttpClient client = new OkHttpClient(); String run(String url) throws IOException { Request request = new Request.Builder().url(url).build(); Response response = client.newCall(request).execute(); if (response.isSuccessful()) { return response.body().string(); } else { throw new IOException( "Unexpected code " + response); } } |
Request是OkHttp中访问的请求,Builder是辅助类。Response即OkHttp中的响应。
Response类:
1
2
3
|
public boolean isSuccessful() Returns true if the code is in [200..300), which means the request was successfully received, understood, and accepted. |
response.body()返回ResponseBody类
可以方便的获取string
1
2
3
4
|
public final String string() throws IOException Returns the response as a string decoded with the charset of the Content-Type header. If that header is either absent or lacks a charset, this will attempt to decode the response body as UTF-8.Throws: IOException |
当然也能获取到流的形式:
1
|
public final InputStream byteStream() |
HTTP POST
POST提交Json数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public static final MediaType JSON = MediaType.parse( "application/json; charset=utf-8" ); OkHttpClient client = new OkHttpClient(); String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(body) .build(); Response response = client.newCall(request).execute(); f (response.isSuccessful()) { return response.body().string(); } else { throw new IOException( "Unexpected code " + response); } } |
使用Request的post方法来提交请求体RequestBody
POST提交键值对
很多时候我们会需要通过POST方式把键值对数据传送到服务器。 OkHttp提供了很方便的方式来做这件事情。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
OkHttpClient client = new OkHttpClient(); String post(String url, String json) throws IOException { RequestBody formBody = new FormEncodingBuilder() .add( "platform" , "android" ) .add( "name" , "bug" ) .add( "subject" , "XXXXXXXXXXXXXXX" ) .build(); Request request = new Request.Builder() .url(url) .post(body) .build(); Response response = client.newCall(request).execute(); if (response.isSuccessful()) { return response.body().string(); } else { throw new IOException( "Unexpected code " + response); } } |
总结
通过上面的例子我们可以发现,OkHttp在很多时候使用都是很方便的,而且很多代码也有重复,因此特地整理了下面的工具类。
注意:
OkHttp官方文档并不建议我们创建多个OkHttpClient,因此全局使用一个。 如果有需要,可以使用clone方法,再进行自定义。这点在后面的高级教程里会提到。
enqueue为OkHttp提供的异步方法,入门教程中并没有提到,后面的高级教程里会有解释。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
import java.io.IOException; import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.message.BasicNameValuePair; import cn.wiz.sdk.constant.WizConstant; import com.squareup.okhttp.Callback; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; public class OkHttpUtil { private static final OkHttpClient mOkHttpClient = new OkHttpClient(); static{ mOkHttpClient.setConnectTimeout(30, TimeUnit.SECONDS); } /** * 该不会开启异步线程。 * @param request * @return * @throws IOException */ public static Response execute(Request request) throws IOException{ return mOkHttpClient.newCall(request).execute(); } /** * 开启异步线程访问网络 * @param request * @param responseCallback */ public static void enqueue(Request request, Callback responseCallback){ mOkHttpClient.newCall(request).enqueue(responseCallback); } /** * 开启异步线程访问网络, 且不在意返回结果(实现空callback) * @param request */ public static void enqueue(Request request){ mOkHttpClient.newCall(request).enqueue( new Callback() { @Override public void onResponse(Response arg0) throws IOException { } @Override public void onFailure(Request arg0, IOException arg1) { } }); } public static String getStringFromServer(String url) throws IOException{ Request request = new Request.Builder().url(url).build(); Response response = execute(request); if (response.isSuccessful()) { String responseUrl = response.body().string(); return responseUrl; } else { throw new IOException( "Unexpected code " + response); } } private static final String CHARSET_NAME = "UTF-8" ; /** * 这里使用了HttpClinet的API。只是为了方便 * @param params * @return */ public static String formatParams(List<BasicNameValuePair> params){ return URLEncodedUtils.format(params, CHARSET_NAME); } /** * 为HttpGet 的 url 方便的添加多个name value 参数。 * @param url * @param params * @return */ public static String attachHttpGetParams(String url, List<BasicNameValuePair> params){ return url + "?" + formatParams(params); } /** * 为HttpGet 的 url 方便的添加1个name value 参数。 * @param url * @param name * @param value * @return */ public static String attachHttpGetParam(String url, String name, String value){ return url + "?" + name + "=" + value; } } |
高级
高级属性其实用的不多,这里主要是对OkHttp github官方教程进行了翻译。
同步get
下载一个文件,打印他的响应头,以string形式打印响应体。
响应体的 string()
方法对于小文档来说十分方便、高效。但是如果响应体太大(超过1MB),应避免适应 string()
方法 ,因为他会将把整个文档加载到内存中。
对于超过1MB的响应body,应使用流的方式来处理body。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); Headers responseHeaders = response.headers(); for (int i = 0; i < responseHeaders.size(); i++) { System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i)); } System.out.println(response.body().string()); } |
异步get
在一个工作线程中下载文件,当响应可读时回调Callback接口。读取响应时会阻塞当前线程。OkHttp现阶段不提供异步api来接收响应体。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .build(); client.newCall(request).enqueue( new Callback() { @Override public void onFailure(Request request, Throwable throwable) { throwable.printStackTrace(); } @Override public void onResponse(Response response) throws IOException { if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); Headers responseHeaders = response.headers(); for (int i = 0; i < responseHeaders.size(); i++) { System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i)); } System.out.println(response.body().string()); } }); } |
提取响应头
典型的HTTP头 像是一个 Map<String, String>
:每个字段都有一个或没有值。但是一些头允许多个值,像Guava的Multimap。例如:HTTP响应里面提供的Vary
响应头,就是多值的。OkHttp的api试图让这些情况都适用。
当写请求头的时候,使用header(name, value)
可以设置唯一的name、value。如果已经有值,旧的将被移除,然后添加新的。使用addHeader(name, value)
可以添加多值(添加,不移除已有的)。
当读取响应头时,使用header(name)
返回最后出现的name、value。通常情况这也是唯一的name、value。如果没有值,那么header(name)
将返回null。如果想读取字段对应的所有值,使用headers(name)
会返回一个list。
为了获取所有的Header,Headers类支持按index访问。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .header( "User-Agent" , "OkHttp Headers.java" ) .addHeader( "Accept" , "application/json; q=0.5" ) .addHeader( "Accept" , "application/vnd.github.v3+json" ) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); System.out.println( "Server: " + response.header( "Server" )); System.out.println( "Date: " + response.header( "Date" )); System.out.println( "Vary: " + response.headers( "Vary" )); } |
Post方式提交String
使用HTTP POST提交请求到服务。这个例子提交了一个markdown文档到web服务,以HTML方式渲染markdown。因为整个请求体都在内存中,因此避免使用此api提交大文档(大于1MB)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse( "text/x-markdown; charset=utf-8" ); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { String postBody = "" + "Releases\n" + "--------\n" + "\n" + " * _1.0_ May 6, 2013\n" + " * _1.1_ June 15, 2013\n" + " * _1.2_ August 11, 2013\n" ; Request request = new Request.Builder() .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody)) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); System.out.println(response.body().string()); } |
Post方式提交流
以流的方式POST提交请求体。请求体的内容由流写入产生。这个例子是流直接写入Okio的BufferedSink。你的程序可能会使用OutputStream
,你可以使用BufferedSink.outputStream()
来获取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse( "text/x-markdown; charset=utf-8" ); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { RequestBody requestBody = new RequestBody() { @Override public MediaType contentType() { return MEDIA_TYPE_MARKDOWN; } @Override public void writeTo(BufferedSink sink) throws IOException { sink.writeUtf8( "Numbers\n" ); sink.writeUtf8( "-------\n" ); for (int i = 2; i <= 997; i++) { sink.writeUtf8(String.format( " * %s = %s\n" , i, factor(i))); } } private String factor(int n) { for (int i = 2; i < n; i++) { int x = n / i; if (x * i == n) return factor(x) + " × " + i; } return Integer.toString(n); } }; Request request = new Request.Builder() .post(requestBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); System.out.println(response.body().string()); } |
Post方式提交文件
以文件作为请求体是十分简单的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse( "text/x-markdown; charset=utf-8" ); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { File file = new File( "README.md" ); Request request = new Request.Builder() .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); System.out.println(response.body().string()); } |
Post方式提交表单
使用FormEncodingBuilder
来构建和HTML<form>
标签相同效果的请求体。键值对将使用一种HTML兼容形式的URL编码来进行编码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { RequestBody formBody = new FormEncodingBuilder() .add( "search" , "Jurassic Park" ) .build(); Request request = new Request.Builder() .post(formBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); System.out.println(response.body().string()); } |
Post方式提交分块请求
MultipartBuilder
可以构建复杂的请求体,与HTML文件上传形式兼容。多块请求体中每块请求都是一个请求体,可以定义自己的请求头。这些请求头可以用来描述这块请求,例如他的Content-Disposition
。如果Content-Length
和Content-Type
可用的话,他们会被自动添加到请求头中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
private static final String IMGUR_CLIENT_ID = "..." ; private static final MediaType MEDIA_TYPE_PNG = MediaType.parse( "image/png" ); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image RequestBody requestBody = new MultipartBuilder() .type(MultipartBuilder.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) .post(requestBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); System.out.println(response.body().string()); } |
使用Gson来解析JSON响应
Gson是一个在JSON和Java对象之间转换非常方便的api。这里我们用Gson来解析Github API的JSON响应。
注意:ResponseBody.charStream()
使用响应头Content-Type
指定的字符集来解析响应体。默认是UTF-8。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
private final OkHttpClient client = new OkHttpClient(); private final Gson gson = new Gson(); public void run() throws Exception { Request request = new Request.Builder() .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); Gist gist = gson.fromJson(response.body().charStream(), Gist.class); for (Map.Entry<String, GistFile> entry : gist.files.entrySet()) { System.out.println(entry.getKey()); System.out.println(entry.getValue().content); } } static class Gist { Map<String, GistFile> files; } static class GistFile { String content; } |
响应缓存
为了缓存响应,你需要一个你可以读写的缓存目录,和缓存大小的限制。这个缓存目录应该是私有的,不信任的程序应不能读取缓存内容。
一个缓存目录同时拥有多个缓存访问是错误的。大多数程序只需要调用一次new OkHttp()
,在第一次调用时配置好缓存,然后其他地方只需要调用这个实例就可以了。否则两个缓存示例互相干扰,破坏响应缓存,而且有可能会导致程序崩溃。
响应缓存使用HTTP头作为配置。你可以在请求头中添加Cache-Control: max-stale=3600
,OkHttp缓存会支持。你的服务通过响应头确定响应缓存多长时间,例如使用Cache-Control: max-age=9600
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
private final OkHttpClient client; public CacheResponse(File cacheDirectory) throws Exception { int cacheSize = 10 * 1024 * 1024; // 10 MiB Cache cache = new Cache(cacheDirectory, cacheSize); client = new OkHttpClient(); client.setCache(cache); } public void run() throws Exception { Request request = new Request.Builder() .build(); Response response1 = client.newCall(request).execute(); if (!response1.isSuccessful()) throw new IOException( "Unexpected code " + response1); String response1Body = response1.body().string(); System.out.println( "Response 1 response: " + response1); System.out.println( "Response 1 cache response: " + response1.cacheResponse()); System.out.println( "Response 1 network response: " + response1.networkResponse()); Response response2 = client.newCall(request).execute(); if (!response2.isSuccessful()) throw new IOException( "Unexpected code " + response2); String response2Body = response2.body().string(); System.out.println( "Response 2 response: " + response2); System.out.println( "Response 2 cache response: " + response2.cacheResponse()); System.out.println( "Response 2 network response: " + response2.networkResponse()); System.out.println( "Response 2 equals Response 1? " + response1Body.equals(response2Body)); } |
扩展
在这一节还提到了下面一句:
There are cache headers to force a cached response, force a network response, or force the network response to be validated with a conditional GET.
我不是很懂cache,平时用到的也不多,所以把Google在Android Developers一段相关的解析放到这里吧。
Force a Network Response
In some situations, such as after a user clicks a 'refresh' button, it may be necessary to skip the cache, and fetch data directly from the server. To force a full refresh, add the no-cache directive:
- connection.addRequestProperty("Cache-Control", "no-cache");
If it is only necessary to force a cached response to be validated by the server, use the more efficient max-age=0 instead:
- connection.addRequestProperty("Cache-Control", "max-age=0");
Force a Cache Response
Sometimes you'll want to show resources if they are available immediately, but not otherwise. This can be used so your application can show something while waiting for the latest data to be downloaded. To restrict a request to locally-cached resources, add the only-if-cached directive:
1
2
3
4
5
6
7
8
|
try { connection.addRequestProperty( "Cache-Control" , "only-if-cached" ); InputStream cached = connection.getInputStream(); // the resource was cached! show it catch (FileNotFoundException e) { // the resource was not cached } } |
This technique works even better in situations where a stale response is better than no response. To permit stale cached responses, use the max-stale directive with the maximum staleness in seconds:
1
|
int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks staleconnection.addRequestProperty("Cache-Control", "max-stale=" + maxStale); |
以上信息来自:HttpResponseCache - Android SDK | Android Developers
取消一个Call
使用Call.cancel()
可以立即停止掉一个正在执行的call。如果一个线程正在写请求或者读响应,将会引发IOException
。当call没有必要的时候,使用这个api可以节约网络资源。例如当用户离开一个应用时。不管同步还是异步的call都可以取消。
你可以通过tags来同时取消多个请求。当你构建一请求时,使用RequestBuilder.tag(tag)
来分配一个标签。之后你就可以用OkHttpClient.cancel(tag)
来取消所有带有这个tag的call。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .build(); final long startNanos = System.nanoTime(); final Call call = client.newCall(request); // Schedule a job to cancel the call in 1 second. executor.schedule( new Runnable() { @Override public void run() { System.out.printf( "%.2f Canceling call.%n" , (System.nanoTime() - startNanos) / 1e9f); call.cancel(); System.out.printf( "%.2f Canceled call.%n" , (System.nanoTime() - startNanos) / 1e9f); } }, 1, TimeUnit.SECONDS); try { System.out.printf( "%.2f Executing call.%n" , (System.nanoTime() - startNanos) / 1e9f); Response response = call.execute(); System.out.printf( "%.2f Call was expected to fail, but completed: %s%n" , (System.nanoTime() - startNanos) / 1e9f, response); } catch (IOException e) { System.out.printf( "%.2f Call failed as expected: %s%n" , (System.nanoTime() - startNanos) / 1e9f, e); } } |
超时
没有响应时使用超时结束call。没有响应的原因可能是客户点链接问题、服务器可用性问题或者这之间的其他东西。OkHttp支持连接,读取和写入超时。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
private final OkHttpClient client; public ConfigureTimeouts() throws Exception { client = new OkHttpClient(); client.setConnectTimeout(10, TimeUnit.SECONDS); client.setWriteTimeout(10, TimeUnit.SECONDS); client.setReadTimeout(30, TimeUnit.SECONDS); } public void run() throws Exception { Request request = new Request.Builder() .build(); Response response = client.newCall(request).execute(); System.out.println( "Response completed: " + response); } |
每个call的配置
使用OkHttpClient
,所有的HTTP Client配置包括代理设置、超时设置、缓存设置。当你需要为单个call改变配置的时候,clone 一个OkHttpClient
。这个api将会返回一个浅拷贝(shallow copy),你可以用来单独自定义。下面的例子中,我们让一个请求是500ms的超时、另一个是3000ms的超时。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .build(); try { Response response = client.clone() // Clone to make a customized OkHttp for this request. .setReadTimeout(500, TimeUnit.MILLISECONDS) .newCall(request) .execute(); System.out.println( "Response 1 succeeded: " + response); } catch (IOException e) { System.out.println( "Response 1 failed: " + e); } try { Response response = client.clone() // Clone to make a customized OkHttp for this request. .setReadTimeout(3000, TimeUnit.MILLISECONDS) .newCall(request) .execute(); System.out.println( "Response 2 succeeded: " + response); } catch (IOException e) { System.out.println( "Response 2 failed: " + e); } } |
处理验证
这部分和HTTP AUTH有关。
相关资料:HTTP AUTH 那些事 - 王绍全的博客 - 博客频道 - CSDN.NET
OkHttp会自动重试未验证的请求。当响应是401 Not Authorized
时,Authenticator
会被要求提供证书。Authenticator的实现中需要建立一个新的包含证书的请求。如果没有证书可用,返回null来跳过尝试。
1
2
3
4
5
6
|
public List<Challenge> challenges() Returns the authorization challenges appropriate for this response's code. If the response code is 401 unauthorized, this returns the "WWW-Authenticate" challenges. If the response code is 407 proxy unauthorized, this returns the "Proxy-Authenticate" challenges. Otherwise this returns an empty list of challenges. |
当需要实现一个Basic
challenge, 使用Credentials.basic(username, password)
来编码请求头。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
private final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { client.setAuthenticator( new Authenticator() { @Override public Request authenticate(Proxy proxy, Response response) { System.out.println( "Authenticating for response: " + response); System.out.println( "Challenges: " + response.challenges()); String credential = Credentials.basic( "jesse" , "password1" ); return response.request().newBuilder() .header( "Authorization" , credential) .build(); } @Override public Request authenticateProxy(Proxy proxy, Response response) { return null ; // Null indicates no attempt to authenticate. } }); Request request = new Request.Builder() .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException( "Unexpected code " + response); System.out.println(response.body().string()); } |
转自 OkHttp使用介绍 同时整合了 OkHttp使用进阶 这篇文章以及其中的评论。
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html
OkHttp使用教程的更多相关文章
- OkHttp使用进阶(译自OkHttp官方教程)
没有使用过OkHttp的,可以先看OkHttp使用介绍 英文版原版地址 Recipes · square/okhttp Wiki 同步get 下载一个文件,打印他的响应头,以string形式打印响应体 ...
- OkHttp使用教程——网络操作之OkHttp, Volley以及Gson
写这篇文章的动机 在安卓项目中有一个问题可能无法避免:网络.不管你是加载图片,请求API数据还是从因特网上获得一个字节,你都是在使用网络. 鉴于网络在安卓中的重要性与基础性,当今安卓开发者面临的问题之 ...
- Android OkHttp完全解析 --zz
参考文章 https://github.com/square/okhttp http://square.github.io/okhttp/ 泡网OkHttp使用教程 Android OkHttp完全解 ...
- Android OkHttp完全解析 是时候来了解OkHttp了
Android OkHttp完全解析 是时候来了解OkHttp了 标签: AndroidOkHttp 2015-08-24 15:36 316254人阅读 评论(306) 收藏 举报 分类: [an ...
- [转] Android OkHttp完全解析 是时候来了解OkHttp了
http://blog.csdn.net/lmj623565791/article/details/47911083: 本文出自:[张鸿洋的博客] 一.概述 最近在群里听到各种讨论okhttp的话题, ...
- 安卓网络请求之——OkHttp学习
之前做安卓项目的时候,HTTP请求用的是android api中的HttpURLConnection和HttpClient,编码比较繁琐,自己封装的也不好.后来知道有很多网络请求的第三方框架,可以方便 ...
- Retrofit 2.0 超能实践(一),okHttp完美支持Https传输
http: //blog.csdn.net/sk719887916/article/details/51597816 Tamic首发 前阵子看到圈子里Retrofit 2.0,RxJava(Andro ...
- Android必知必会-使用okhttp的PUT方式上传文件
注:如果移动端排版有问题,请看 简书版 (<-点击左边),希望CSDN能更好的支持移动端. 背景 公司的文件上传接口使用PUT协议,之前一直用的都是老项目中的上传类,现在项目中使用了okhttp ...
- 基本使用——OkHttp3详细使用教程
基本使用——OkHttp3详细使用教程 转 https://blog.csdn.net/xx326664162/article/details/77714126 概述 OkHttp现在应该算是最火的H ...
随机推荐
- Sql与MySQL简单入门
作为过来人,给"新司机"一点建议:运维时需要搭建的生产环境,需尽量保持与测试环境一致:但搭建环境时,又苦于找不到合适的版本怎么办?不用怕,我是一个体贴的人,管杀也管埋(该链接为My ...
- SAM4E单片机之旅——24、使用DSP库求向量数量积
DSP(Digital Signal Processing,数字信号处理)中会使用大量的数学运算.Cortex-M4中,配置了一些强大的部件,以提高DSP能力.同时CMSIS提供了一个DSP库,提供了 ...
- Java Se:自定义ClassLoader
JVM是如何知道java.lang包中的类的?JVM又是如何知道我们应用中的类的?我们的应用中明明是有某个类, 但是JVM却抛出ClassNotFoundException,这是为什么?XxxImpl ...
- 《java JDK7 学习笔记》课后练习题3
1.如果有以下的程序代码:int number;System.out.println(number);以下描述何者正确?A.执行时显示0B.执行时显示随机数字C.执行时出现错误D.编译失败 2.如果有 ...
- java web 开发 购物车功能的实现
为了方便自己以后复习,所以写的比较仔细,记录下自己的成长..... 既然是做购物车,那么前提条件是首先需要一系列商品,也就是要建一个实体,这里建了一个商品表. 通过查询在浏览器上显示 基本显示已经做好 ...
- Nginx状态码499
1.问题描述 140.207.202.187 - - [18/May/2016:10:30:58 +0800] "POST/v3/violations HTTP/1.1" 499 ...
- [整]SQL执行顺序
SQL的执行顺序: 第一步:FROM <left_table> <join_type> JOIN <right_table> ON <on_predicate ...
- arcgis 随手记
1,ArcGISDynamicMapServiceLayer 3.0 用 4.1 以后用MapImageLayer 代码如下: <!DOCTYPE html> <html&g ...
- mysql字符编码集(乱码)问题解决
1.创建数据库 CREATE DATABASE `test` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'; 创建表 CREATE TABLE tp_w ...
- 烂泥:ESXI开启SNMP服务
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 要监控ESXI,打算通过snmp方式进行监控,这样操作比较简单.但是要使用SNMP方式进行监控,必须要开启ESXI的SNMP服务.ESXI由于版本号的不 ...