Android:OkHttp的理解和使用
OkHttp的理解和使用
- OkHttp
- 1、什么是OkHttp
- 2、OkHttp的作用
- 3、Okhttp的基本使用
- 3.1、Http請(qǐng)求和響應(yīng)的組成
- 3.2、OkHttp請(qǐng)求和響應(yīng)的組成
- 3.3、GET請(qǐng)求同步方法
- 3.4、GET請(qǐng)求異步方法
- 3.5、post請(qǐng)求方法
- 3.6、POST請(qǐng)求傳遞參數(shù)的方法總結(jié)
- 3.6.1、Post方式提交String
- 3.6.2、Post方式提交 `流`
- 3.6.3、Post方式提交文件
- 3.6.4、Post方式提交表單
- 3.7、POST其他用法
- 3.7.1、提取響應(yīng)頭
- 3.7.2、使用Gson來解析JSON響應(yīng)
- 3.7.3、響應(yīng)緩存
- 3.7.4、響應(yīng)cookie
- 3.8、綜合實(shí)例
- 參考
OkHttp
1、什么是OkHttp
1、網(wǎng)絡(luò)請(qǐng)求發(fā)展
歷史上Http請(qǐng)求庫優(yōu)缺點(diǎn)
HttpURLConnection—>Apache HTTP Client—>Volley—->okHttp
2、項(xiàng)目開源地址
https://github.com/square/okhttp
3、OkHttp是什么
- OKhttp是一個(gè)網(wǎng)絡(luò)請(qǐng)求開源項(xiàng)目,Android網(wǎng)絡(luò)請(qǐng)求輕量級(jí)框架,支持文件上傳與下載,支持https。
2、OkHttp的作用
OkHttp是一個(gè)高效的HTTP庫:
- 支持HTTP/2, HTTP/2通過使用多路復(fù)用技術(shù)在一個(gè)單獨(dú)的TCP連接上支持并發(fā), 通過在一個(gè)連接上一次性發(fā)送多個(gè)請(qǐng)求來發(fā)送或接收數(shù)據(jù)
- 如果HTTP/2不可用, 連接池復(fù)用技術(shù)也可以極大減少延時(shí)
- 支持GZIP, 可以壓縮下載體積
- 響應(yīng)緩存可以直接避免重復(fù)請(qǐng)求
- 會(huì)從很多常用的連接問題中自動(dòng)恢復(fù)
- 如果您的服務(wù)器配置了多個(gè)IP地址, 當(dāng)?shù)谝粋€(gè)IP連接失敗的時(shí)候, OkHttp會(huì)自動(dòng)嘗試下一個(gè)IP OkHttp還處理了代理服務(wù)器問題和SSL握手失敗問題
優(yōu)勢(shì)
- 使用 OkHttp無需重寫您程序中的網(wǎng)絡(luò)代碼。OkHttp實(shí)現(xiàn)了幾乎和java.net.HttpURLConnection一樣的API。如果您用了 Apache HttpClient,則OkHttp也提供了一個(gè)對(duì)應(yīng)的okhttp-apache 模塊
3、Okhttp的基本使用
Okhttp的基本使用,從以下五方面講解:
- 1.Get請(qǐng)求(同步和異步)
- 2.POST請(qǐng)求表單(key-value)
- 3.POST請(qǐng)求提交(JSON/String/文件等)
- 4.文件下載
- 5.請(qǐng)求超時(shí)設(shè)置
加入build.gradle
compile 'com.squareup.okhttp3:okhttp:3.6.0'3.1、Http請(qǐng)求和響應(yīng)的組成
http請(qǐng)求
所以一個(gè)類庫要完成一個(gè)http請(qǐng)求, 需要包含 請(qǐng)求方法, 請(qǐng)求地址, 請(qǐng)求協(xié)議, 請(qǐng)求頭, 請(qǐng)求體這五部分. 這些都在okhttp3.Request的類中有體現(xiàn), 這個(gè)類正是代表http請(qǐng)求的類. 看下圖:
其中HttpUrl類代表請(qǐng)求地址, String method代表請(qǐng)求方法, Headers代表請(qǐng)求頭, RequestBody代表請(qǐng)求體. Object tag這個(gè)是用來取消http請(qǐng)求的標(biāo)志, 這個(gè)我們先不管.
http響應(yīng)
響應(yīng)組成圖:
可以看到大體由應(yīng)答首行, 應(yīng)答頭, 應(yīng)答體構(gòu)成. 但是應(yīng)答首行表達(dá)的信息過多, HTTP/1.1表示訪問協(xié)議, 200是響應(yīng)碼, OK是描述狀態(tài)的消息.
根據(jù)單一職責(zé), 我們不應(yīng)該把這么多內(nèi)容用一個(gè)應(yīng)答首行來表示. 這樣的話, 我們的響應(yīng)就應(yīng)該由訪問協(xié)議, 響應(yīng)碼, 描述信息, 響應(yīng)頭, 響應(yīng)體來組成.
3.2、OkHttp請(qǐng)求和響應(yīng)的組成
OkHttp請(qǐng)求
構(gòu)造一個(gè)http請(qǐng)求, 并查看請(qǐng)求具體內(nèi)容:
final Request request = new Request.Builder().url("https://github.com/").build();我們看下在內(nèi)存中, 這個(gè)請(qǐng)求是什么樣子的, 是否如我們上文所說和請(qǐng)求方法, 請(qǐng)求地址, 請(qǐng)求頭, 請(qǐng)求體一一對(duì)應(yīng).
OkHttp響應(yīng)
OkHttp庫怎么表示一個(gè)響應(yīng):
可以看到Response類里面有Protocol代表請(qǐng)求協(xié)議, int code代表響應(yīng)碼, String message代表描述信息, Headers代表響應(yīng)頭, ResponseBody代表響應(yīng)體. 當(dāng)然除此之外, 還有Request代表持有的請(qǐng)求, Handshake代表SSL/TLS握手協(xié)議驗(yàn)證時(shí)的信息, 這些額外信息我們暫時(shí)不問.
有了剛才說的OkHttp響應(yīng)的類組成, 我們看下OkHttp請(qǐng)求后響應(yīng)在內(nèi)存中的內(nèi)容:
final Request request = new Request.Builder().url("https://github.com/").build(); Response response = client.newCall(request).execute();3.3、GET請(qǐng)求同步方法
同步GET的意思是一直等待http請(qǐng)求, 直到返回了響應(yīng). 在這之間會(huì)阻塞進(jìn)程, 所以通過get不能在Android的主線程中執(zhí)行, 否則會(huì)報(bào)錯(cuò).
對(duì)于同步請(qǐng)求在請(qǐng)求時(shí)需要開啟子線程,請(qǐng)求成功后需要跳轉(zhuǎn)到UI線程修改UI。
public void getDatasync(){new Thread(new Runnable() {@Overridepublic void run() {try {OkHttpClient client = new OkHttpClient();//創(chuàng)建OkHttpClient對(duì)象Request request = new Request.Builder().url("http://www.baidu.com")//請(qǐng)求接口。如果需要傳參拼接到接口后面。.build();//創(chuàng)建Request 對(duì)象Response response = null;response = client.newCall(request).execute();//得到Response 對(duì)象if (response.isSuccessful()) {Log.d("kwwl","response.code()=="+response.code());Log.d("kwwl","response.message()=="+response.message());Log.d("kwwl","res=="+response.body().string());//此時(shí)的代碼執(zhí)行在子線程,修改UI的操作請(qǐng)使用handler跳轉(zhuǎn)到UI線程。}} catch (Exception e) {e.printStackTrace();}}}).start(); }此時(shí)打印結(jié)果如下:
response.code()==200; response.message()OK; res{“code”:200,“message”:success};OkHttpClient實(shí)現(xiàn)了Call.Factory接口, 是Call的工廠類, Call負(fù)責(zé)發(fā)送執(zhí)行請(qǐng)求和讀取響應(yīng).
Request代表Http請(qǐng)求, 通過Request.Builder輔助類來構(gòu)建.
client.newCall(request)通過傳入一個(gè)http request, 返回一個(gè)Call調(diào)用. 然后執(zhí)行execute()方法, 同步獲得Response代表Http請(qǐng)求的響應(yīng). response.body()是ResponseBody類, 代表響應(yīng)體
注意事項(xiàng):
1,Response.code是http響應(yīng)行中的code,如果訪問成功則返回200.這個(gè)不是服務(wù)器設(shè)置的,而是http協(xié)議中自帶的。res中的code才是服務(wù)器設(shè)置的。注意二者的區(qū)別。
2,response.body().string()本質(zhì)是輸入流的讀操作,所以它還是網(wǎng)絡(luò)請(qǐng)求的一部分,所以這行代碼必須放在子線程。
3,response.body().string()只能調(diào)用一次,在第一次時(shí)有返回值,第二次再調(diào)用時(shí)將會(huì)返回null。原因是:response.body().string()的本質(zhì)是輸入流的讀操作,必須有服務(wù)器的輸出流的寫操作時(shí)客戶端的讀操作才能得到數(shù)據(jù)。而服務(wù)器的寫操作只執(zhí)行一次,所以客戶端的讀操作也只能執(zhí)行一次,第二次將返回null。
4、響應(yīng)體的string()方法對(duì)于小文檔來說十分方便高效. 但是如果響應(yīng)體太大(超過1MB), 應(yīng)避免使用 string()方法, 因?yàn)樗鼤?huì)將把整個(gè)文檔加載到內(nèi)存中.
5、對(duì)于超過1MB的響應(yīng)body, 應(yīng)使用流的方式來處理響應(yīng)body. 這和我們處理xml文檔的邏輯是一致的, 小文件可以載入內(nèi)存樹狀解析, 大文件就必須流式解析.
注解:
responseBody.string()獲得字符串的表達(dá)形式, 或responseBody.bytes()獲得字節(jié)數(shù)組的表達(dá)形式, 這兩種形式都會(huì)把文檔加入到內(nèi)存. 也可以通過responseBody.charStream()和responseBody.byteStream()返回流來處理.
3.4、GET請(qǐng)求異步方法
異步GET是指在另外的工作線程中執(zhí)行http請(qǐng)求, 請(qǐng)求時(shí)不會(huì)阻塞當(dāng)前的線程, 所以可以在Android主線程中使用.
這種方式不用再次開啟子線程,但回調(diào)方法是執(zhí)行在子線程中,所以在更新UI時(shí)還要跳轉(zhuǎn)到UI線程中。
下面是在一個(gè)工作線程中下載文件, 當(dāng)響應(yīng)可讀時(shí)回調(diào)Callback接口. 當(dāng)響應(yīng)頭準(zhǔn)備好后, 就會(huì)調(diào)用Callback接口, 所以讀取響應(yīng)體時(shí)可能會(huì)阻塞. OkHttp現(xiàn)階段不提供異步api來接收響應(yīng)體。
private final OkHttpClient client = new OkHttpClient();public void run() throws Exception {Request request = new Request.Builder().url("http://publicobject.com/helloworld.txt").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());}}); }異步請(qǐng)求的打印結(jié)果與注意事項(xiàng)與同步請(qǐng)求時(shí)相同。最大的不同點(diǎn)就是異步請(qǐng)求不需要開啟子線程,enqueue方法會(huì)自動(dòng)將網(wǎng)絡(luò)請(qǐng)求部分放入子線程中執(zhí)行。
注意事項(xiàng):
- 1,回調(diào)接口的onFailure方法和onResponse執(zhí)行在子線程。
- 2,response.body().string()方法也必須放在子線程中。當(dāng)執(zhí)行這行代碼得到結(jié)果后,再跳轉(zhuǎn)到UI線程修改UI。
3.5、post請(qǐng)求方法
Post請(qǐng)求也分同步和異步兩種方式,同步與異步的區(qū)別和get方法類似,所以此時(shí)只講解post異步請(qǐng)求的使用方法。
private void postDataWithParame() {OkHttpClient client = new OkHttpClient();//創(chuàng)建OkHttpClient對(duì)象。FormBody.Builder formBody = new FormBody.Builder();//創(chuàng)建表單請(qǐng)求體formBody.add("username","zhangsan");//傳遞鍵值對(duì)參數(shù)Request request = new Request.Builder()//創(chuàng)建Request 對(duì)象。.url("http://www.baidu.com").post(formBody.build())//傳遞請(qǐng)求體.build();client.newCall(request).enqueue(new Callback() {。。。});//回調(diào)方法的使用與get異步請(qǐng)求相同,此時(shí)略。 }看完代碼我們會(huì)發(fā)現(xiàn):post請(qǐng)求中并沒有設(shè)置請(qǐng)求方式為POST,回憶在get請(qǐng)求中也沒有設(shè)置請(qǐng)求方式為GET,那么是怎么區(qū)分請(qǐng)求方式的呢?重點(diǎn)是Request.Builder類的post方法,在Request.Builder對(duì)象創(chuàng)建最初默認(rèn)是get請(qǐng)求,所以在get請(qǐng)求中不需要設(shè)置請(qǐng)求方式,當(dāng)調(diào)用post方法時(shí)把請(qǐng)求方式修改為POST。所以此時(shí)為POST請(qǐng)求。
3.6、POST請(qǐng)求傳遞參數(shù)的方法總結(jié)
3.6.1、Post方式提交String
下面是使用HTTP POST提交請(qǐng)求到服務(wù). 這個(gè)例子提交了一個(gè)markdown文檔到web服務(wù), 以HTML方式渲染markdown. 因?yàn)檎麄€(gè)請(qǐng)求體都在內(nèi)存中, 因此避免使用此api提交大文檔(大于1MB).
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().url("https://api.github.com/markdown/raw").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()); }3.6.2、Post方式提交 流
以流的方式POST提交請(qǐng)求體. 請(qǐng)求體的內(nèi)容由流寫入產(chǎn)生. 這個(gè)例子是流直接寫入Okio的BufferedSink. 你的程序可能會(huì)使用OutputStream, 你可以使用BufferedSink.outputStream()來獲取. OkHttp的底層對(duì)流和字節(jié)的操作都是基于Okio庫, Okio庫也是Square開發(fā)的另一個(gè)IO庫, 填補(bǔ)I/O和NIO的空缺, 目的是提供簡單便于使用的接口來操作IO.
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().url("https://api.github.com/markdown/raw").post(requestBody).build();Response response = client.newCall(request).execute();if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);System.out.println(response.body().string()); }3.6.3、Post方式提交文件
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().url("https://api.github.com/markdown/raw").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()); }3.6.4、Post方式提交表單
使用FormEncodingBuilder來構(gòu)建和HTML標(biāo)簽相同效果的請(qǐng)求體. 鍵值對(duì)將使用一種HTML兼容形式的URL編碼來進(jìn)行編碼.
private final OkHttpClient client = new OkHttpClient();public void run() throws Exception {RequestBody formBody = new FormBody.Builder().add("search", "Jurassic Park").build();Request request = new Request.Builder().url("https://en.wikipedia.org/w/index.php").post(formBody).build();Response response = client.newCall(request).execute();if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);System.out.println(response.body().string());}3.7、POST其他用法
3.7.1、提取響應(yīng)頭
典型的HTTP頭像是一個(gè)Map<String, String> : 每個(gè)字段都有一個(gè)或沒有值. 但是一些頭允許多個(gè)值, 像Guava的Multimap
例如:
HTTP響應(yīng)里面提供的Vary響應(yīng)頭, 就是多值的. OkHttp的api試圖讓這些情況都適用.
- 當(dāng)寫請(qǐng)求頭的時(shí)候, 使用header(name, value)可以設(shè)置唯一的name、value. 如果已經(jīng)有值, 舊的將被移除,然后添加新的. 使用addHeader(name, value)可以添加多值(添加, 不移除已有的).
- 當(dāng)讀取響應(yīng)頭時(shí), 使用header(name)返回最后出現(xiàn)的name、value. 通常情況這也是唯一的name、value.如果沒有值, 那么header(name)將返回null. 如果想讀取字段對(duì)應(yīng)的所有值,使用headers(name)會(huì)返回一個(gè)list.
為了獲取所有的Header, Headers類支持按index訪問.
private final OkHttpClient client = new OkHttpClient();public void run() throws Exception {Request request = new Request.Builder().url("https://api.github.com/repos/square/okhttp/issues").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")); }3.7.2、使用Gson來解析JSON響應(yīng)
Gson是一個(gè)在JSON和Java對(duì)象之間轉(zhuǎn)換非常方便的api庫. 這里我們用Gson來解析Github API的JSON響應(yīng).
注意: ResponseBody.charStream()使用響應(yīng)頭Content-Type指定的字符集來解析響應(yīng)體. 默認(rèn)是UTF-8.
private final OkHttpClient client = new OkHttpClient();private final Gson gson = new Gson();public void run() throws Exception {Request request = new Request.Builder().url("https://api.github.com/gists/c2a7c39532239ff261be").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;}3.7.3、響應(yīng)緩存
為了緩存響應(yīng), 你需要一個(gè)你可以讀寫的緩存目錄, 和緩存大小的限制. 這個(gè)緩存目錄應(yīng)該是私有的, 不信任的程序應(yīng)不能讀取緩存內(nèi)容.
一個(gè)緩存目錄同時(shí)擁有多個(gè)緩存訪問是錯(cuò)誤的. 大多數(shù)程序只需要調(diào)用一次new OkHttp(), 在第一次調(diào)用時(shí)配置好緩存, 然后其他地方只需要調(diào)用這個(gè)實(shí)例就可以了. 否則兩個(gè)緩存示例互相干擾, 破壞響應(yīng)緩存, 而且有可能會(huì)導(dǎo)致程序崩潰.
響應(yīng)緩存使用HTTP頭作為配置. 你可以在請(qǐng)求頭中添加Cache-Control: max-stale=3600 , OkHttp緩存會(huì)支持. 你的服務(wù)通過響應(yīng)頭確定響應(yīng)緩存多長時(shí)間, 例如使用Cache-Control: max-age=9600.
private final OkHttpClient client;public CacheResponse(File cacheDirectory) throws Exception {int cacheSize = 10 * 1024 * 1024; // 10 MiBCache cache = new Cache(cacheDirectory, cacheSize);client = new OkHttpClient();client.setCache(cache); }public void run() throws Exception {Request request = new Request.Builder().url("http://publicobject.com/helloworld.txt").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)); }如果需要阻值response使用緩存, 使用CacheControl.FORCE_NETWORK. 如果需要阻值response使用網(wǎng)絡(luò), 使用CacheControl.FORCE_CACHE.
警告
如果你使用FORCE_CACHE, 但是response要求使用網(wǎng)絡(luò), OkHttp將會(huì)返回一個(gè)504 Unsatisfiable Request響應(yīng).
實(shí)例2
package com.enjoy.networkdemo;import android.util.Log;import org.jetbrains.annotations.NotNull; import org.junit.Test;import java.io.File; import java.io.IOException;import okhttp3.Cache; import okhttp3.Call; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response;public class InterceptorUnitTest {@Testpublic void interceptorTest() {OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(new Cache(new File("C:\\Users\\Administrator\\Desktop"),1024 * 1024)).addNetworkInterceptor(new Interceptor() {@NotNull@Overridepublic Response intercept(@NotNull Chain chain) throws IOException {System.out.println("version:" + chain.request().header("version"));return chain.proceed(chain.request());}}).addInterceptor(new Interceptor() {@NotNull@Overridepublic 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();// 準(zhǔn)備好請(qǐng)求的Call對(duì)象Call call = okHttpClient.newCall(request);try {Response response = call.execute();System.out.println(response.body().string());} catch (IOException e) {e.printStackTrace();}} }3.7.4、響應(yīng)cookie
package com.enjoy.networkdemo;import org.jetbrains.annotations.NotNull; import org.junit.Test;import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;import okhttp3.Cache; import okhttp3.Call; import okhttp3.Cookie; import okhttp3.CookieJar; import okhttp3.FormBody; import okhttp3.HttpUrl; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response;public class CookieUnitTest {Map<String, List<Cookie>> cookies = new HashMap<>();@Testpublic void cookieTest() {OkHttpClient okHttpClient = new OkHttpClient.Builder().cookieJar(new CookieJar() {@Overridepublic void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {cookies.put(httpUrl.host(), list);}@NotNull@Overridepublic 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();// 準(zhǔn)備好請(qǐng)求的Call對(duì)象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();// 準(zhǔn)備好請(qǐng)求的Call對(duì)象call = okHttpClient.newCall(request);try {Response response = call.execute();System.out.println(response.body().string());} catch (IOException e) {e.printStackTrace();}} }3.8、綜合實(shí)例
參考鏈接
activity_main
MainActivity
package com.example.okhttpdemo;import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView;import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.TimeUnit;import okhttp3.Call; import okhttp3.Callback; import okhttp3.FormBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response;public class MainActivity extends AppCompatActivity implements View.OnClickListener {private Button syncGet;private Button asyncget;private Button post;private Button fileDownload;private TextView tvtext;private String result;private static OkHttpClient client = new OkHttpClient();/*** 在這里直接設(shè)置連接超時(shí),靜態(tài)方法內(nèi),在構(gòu)造方法被調(diào)用前就已經(jīng)初始話了*/static {client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);client.newBuilder().readTimeout(10, TimeUnit.SECONDS);client.newBuilder().writeTimeout(10, TimeUnit.SECONDS);}private Request request;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initialize();initListener();}/*** 事件監(jiān)聽*/private void initListener() {syncGet.setOnClickListener(this);asyncget.setOnClickListener(this);post.setOnClickListener(this);fileDownload.setOnClickListener(this);}/*** 初始化布局控件*/private void initialize() {syncGet = (Button) findViewById(R.id.syncGet);asyncget = (Button) findViewById(R.id.asyncget);post = (Button) findViewById(R.id.post);tvtext = (TextView) findViewById(R.id.tv_text);fileDownload = (Button) findViewById(R.id.fileDownload);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.syncGet:initSyncData();break;case R.id.asyncget:initAsyncGet();break;case R.id.post:initPost();break;case R.id.fileDownload:downLoadFile();break;default:break;}}/*** get請(qǐng)求同步方法*/private void initSyncData() {new Thread(new Runnable() {@Overridepublic void run() {try {request = new Request.Builder().url(Contants.SYNC_URL).build();Response response = client.newCall(request).execute();result = response.body().string();runOnUiThread(new Runnable() {@Overridepublic void run() {tvtext.setText(result);Log.d("MainActivity", "hello");}});} catch (Exception e) {e.printStackTrace();}}}).start();}/*** 異步請(qǐng)求*/private void initAsyncGet() {new Thread(new Runnable() {@Overridepublic void run() {request = new Request.Builder().url(Contants.ASYNC_URL).build();client.newCall(request).enqueue(new Callback() {/*** @param call 是一個(gè)接口, 是一個(gè)準(zhǔn)備好的可以執(zhí)行的request* 可以取消,對(duì)位一個(gè)請(qǐng)求對(duì)象,只能單個(gè)請(qǐng)求* @param e*/@Overridepublic void onFailure(Call call, IOException e) {Log.d("MainActivity", "請(qǐng)求失敗");}/**** @param call* @param response 是一個(gè)響應(yīng)請(qǐng)求* @throws IOException*/@Overridepublic void onResponse(Call call, Response response) throws IOException {/*** 通過拿到response這個(gè)響應(yīng)請(qǐng)求,然后通過body().string(),拿到請(qǐng)求到的數(shù)據(jù)* 這里最好用string() 而不要用toString()* toString()每個(gè)類都有的,是把對(duì)象轉(zhuǎn)換為字符串* string()是把流轉(zhuǎn)為字符串*/result = response.body().string();runOnUiThread(new Runnable() {@Overridepublic void run() {tvtext.setText(result);}});}});}}).start();}/*** 表單提交*/private void initPost() {String url = "http://112.124.22.238:8081/course_api/banner/query";FormBody formBody = new FormBody.Builder().add("type", "1").build();request = new Request.Builder().url(url).post(formBody).build();new Thread(new Runnable() {@Overridepublic void run() {client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, final Response response) throws IOException {runOnUiThread(new Runnable() {@Overridepublic void run() {tvtext.setText("提交成功");}});}});}}).start();}/*** 文件下載地址*/private void downLoadFile() {String url = "http://www.0551fangchan.com/images/keupload/20120917171535_49309.jpg";request = new Request.Builder().url(url).build();OkHttpClient client = new OkHttpClient();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, Response response) throws IOException {//把請(qǐng)求成功的response轉(zhuǎn)為字節(jié)流InputStream inputStream = response.body().byteStream();/*** 在這里要加上權(quán)限 在mainfests文件中* <uses-permission android:name="android.permission.INTERNET"/>* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>*///在這里用到了文件輸出流FileOutputStream fileOutputStream = new FileOutputStream(new File("/sdcard/logo.jpg"));//定義一個(gè)字節(jié)數(shù)組byte[] buffer = new byte[2048];int len = 0;while ((len = inputStream.read(buffer)) != -1) {//寫出到文件fileOutputStream.write(buffer, 0, len);}//關(guān)閉輸出流fileOutputStream.flush();Log.d("wuyinlei", "文件下載成功...");}});}}參考
1、https://blog.csdn.net/fightingXia/article/details/70947701
2、https://blog.csdn.net/chenzujie/article/details/46994073
3、https://blog.csdn.net/weixin_30700099/article/details/95962192
4、https://www.jianshu.com/p/5a12ae6d741a
5、https://www.jianshu.com/p/ca8a982a116b
6、https://wuyinlei.blog.csdn.net/article/details/50579564
總結(jié)
以上是生活随笔為你收集整理的Android:OkHttp的理解和使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WAP资源
- 下一篇: Android网络通讯之OkHttp