如今基本上全部的網絡框架都採用Okhttp、rxjava、retrofit三者一塊兒寫的。由於最近沒有什麼事情,就抽空總結一下這方面的知識:由於這些東西連在一期講的話,不少同窗會以爲懵逼,因此這裏我準備先講一下每個東西的用法,而後在講解一下怎麼聯合使用。html
最近看了 《X特遣隊/自殺小隊》 以爲不錯。以一種混子的心態生活,其實挺輕鬆的!因此一張圖片鎮樓!習慣的我能夠發給你!java
在這裏先來個重要的說明:網絡權限必定要加,必定要加!!!git
其實關於OkHttp的使用只要記住一個順序就能夠github
基本上記住上面的步驟就能夠實現簡單的請求了!chrome
既然上面都提到了相應的步驟,咱們就按照上面的步驟寫一下就能夠了!!!json
OkHttpClient httpClient = new OkHttpClient();
複製代碼
建立一個對象而已,沒有什麼好說的!!!安全
Request request = new Request.Builder() .method("GET", null) .url("https://www.baidu.com/") .build(); 複製代碼
這裏簡單說一下,method是設置相應的請求方式的;url是設置相應的請求地址的!其次Request是一個構建者的構建模式。剩下的沒有什麼好說的。,若是新手,不用管那麼多爲何,實現效果纔是重要的!!!bash
Call call = httpClient.newCall(request);
複製代碼
這裏其實就是讓httpClient知道本身要請求什麼而已服務器
call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "請求失敗的緣由:" + e); } @Override public void onResponse(Call call, final Response response) throws IOException { Headers headers = response.headers(); Set<String> names = headers.names(); for (String name : names) { Log.e(TAG, "請求的header" + name); String value = headers.get(name); Log.e(TAG, "值爲: " + value + "\n----------------------------------"); } final String date = response.body().string(); mHandler.post(new Runnable() { @Override public void run() { mTvShow.setText(date); } }); } }); 複製代碼
這裏要說明的就多了:markdown
當你的看到FATAL EXCEPTION: OkHttp Dispatcher這個異常的時候,恭喜你,你踩到第一個坑了!這個主要是由於response.body().string()
只能調用一次,若是你在代碼中調用了兩次,那麼就會出現上面的異常;
當你異步請求的時候,是不能在子線程修改UI的,因此這裏我用了一個Handler去操做相應的內容
若是你想看相應的一些內容的話,那麼看那個for循環那裏,你打印一下,就能看到以下的內容,若是不怎麼理解的話,找大家後臺人員請教一下!必定要虛心哦。
Accept-Ranges →bytes Cache-Control →no-cache Connection →Keep-Alive Content-Length →227 Content-Type →text/html Date →Wed, 05 Sep 2018 03:41:58 GMT Etag →"5b7b7f40-e3" Last-Modified →Tue, 21 Aug 2018 02:56:00 GMT Pragma →no-cache Server →BWS/1.1 Set-Cookie →BD_NOT_HTTPS=1; path=/; Max-Age=300 Strict-Transport-Security →max-age=0 X-Ua-Compatible →IE=Edge,chrome=1 複製代碼
若是失敗的話,那麼就會在onFailure中把異常反饋給你!!!
給你貼下總體代碼吧!
/*1.建立OkHttpClient對象*/ OkHttpClient httpClient = new OkHttpClient(); /*2.建立請求Request內容*/ Request request = new Request.Builder() .method("GET", null) .url("https://www.baidu.com/") .build(); /*3.發送請求*/ Call call = httpClient.newCall(request); /*4.建立請求的回調*/ call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "請求失敗的緣由:" + e); } @Override public void onResponse(Call call, final Response response) throws IOException { Headers headers = response.headers(); Set<String> names = headers.names(); for (String name : names) { Log.e(TAG, "請求的header" + name); String value = headers.get(name); Log.e(TAG, "值爲: " + value + "\n----------------------------------"); } final String date = response.body().string(); mHandler.post(new Runnable() { @Override public void run() { mTvShow.setText(date); } }); } }); 複製代碼
以上步驟就能正常請求相應的數據了,若是尚未數據的話,好好看看代碼!
關於POST請求的話,基本上就是比GET請求多一步設置表單的方法,也就是一個FormBody對象的設置,以key、value的方式設置表單而已,因此這裏教你怎麼寫,而後我貼一下代碼就那麼滴了,誰讓我那麼懶呢!!!
表單的寫法是這樣的:
FormBody formBody = new FormBody.Builder() .add("key", "value") .build(); 複製代碼
其實add方法能夠被調用屢次,添加相應的key和value;
總體的代碼是這樣的!!!
/*1.建立OkHttpClient對象*/ OkHttpClient httpClient = new OkHttpClient(); /*2.建立相應的表單內容*/ FormBody formBody = new FormBody.Builder() .add("key", "value") .build(); /*3.建立請求Request內容*/ Request request = new Request.Builder() .url("https://www.baidu.com/") .post(formBody) .build(); /*4.發送請求*/ Call call = httpClient.newCall(request); /*5.建立請求的回調*/ call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "請求失敗的緣由:" + e); } @Override public void onResponse(Call call, final Response response) throws IOException { Headers headers = response.headers(); Set<String> names = headers.names(); for (String name : names) { Log.e(TAG, "請求的header" + name); String value = headers.get(name); Log.e(TAG, "值爲: " + value + "\n----------------------------------"); } final String date = response.body().string(); mHandler.post(new Runnable() { @Override public void run() { mTvShow.setText(date); } }); } }); } 複製代碼
POST和GET請求只是請求的方式不一樣,POST比較安全,全部內容都依靠表單傳遞!
在這裏先來個重要的說明:去寫SD卡的權限必定要加,必定要加!!!
說到文件上傳,通常的網絡請求都帶有文件上傳的功能,其實OkHttp3也能夠上傳文件,具體操做步驟以下:
由於其餘的內容都差很少,只有關於表單的內容不通,因此這裏着重講一下關於這個表單的問題。
RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("title", "張三") .addFormDataPart("image", "zhangsan.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), new File(Environment.getExternalStorageDirectory().getParent() + "/0/123.png"))) .build(); 複製代碼
通常這種上傳文件,基本上都是傳遞相應的用戶圖片,修改圖片什麼的!由於服務器要根據你上傳的這張圖片進行相應圖片的替換。回來講上面那個配置:
總體代碼是這樣的:
/*1.建立OkHttpClient對象*/ OkHttpClient httpClient = new OkHttpClient(); /*2.建立相應的表單內容*/ RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("title", "張三") .addFormDataPart("image", "zhangsan.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), new File(Environment.getExternalStorageDirectory().getParent() + "/0/123.png"))) .build(); /*3.建立請求Request內容*/ Request request = new Request.Builder() .header("key", "value") .url("https://www.baidu.com/") .post(requestBody) .build(); /*4.發送請求*/ Call call = httpClient.newCall(request); /*5.建立請求的回調*/ call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "onFailure: " + e); } @Override public void onResponse(Call call, Response response) throws IOException { Log.e(TAG, "onResponse: " + response.body().string()); } }); 複製代碼
對了忘說了一點,圖片是以流的形式進行傳遞的。因此上面"application/octet-stream"配置的是這種格式,若是是其餘的格式呢?給你們一份對照表:參照一下就OK了。
參數 | 說明 |
---|---|
text/html | HTML格式 |
text/plain | 純文本格式 |
text/xml | XML格式 |
image/gif | gif圖片格式 |
image/jpeg | jpg圖片格式 |
image/png | png圖片格式 |
application/xhtml+xml | XHTML格式 |
application/xml | XML數據格式 |
application/atom+xml | Atom XML聚合格式 |
application/json | JSON數據格式 |
application/pdf | pdf格式 |
application/msword | Word文檔格式 |
application/octet-stream | 二進制流數據 |
基本上你把上面的代碼改吧改吧就能上傳文件了!!!就醬紫簡單。。。
配置請求時間和鏈接超時的時間等等
OkHttpClient httpClient = new OkHttpClient.Builder()
//設置相應的鏈接池
.connectionPool(new ConnectionPool())
//鏈接超時
.connectTimeout(15, TimeUnit.SECONDS)
//寫入超時
.writeTimeout(15, TimeUnit.SECONDS)
//讀取超時
.readTimeout(20, TimeUnit.SECONDS)
.build();
複製代碼
每每在項目中,都會有一些關於公共請求參數的一些問題,這裏就會用到相應的OkHttp攔截器!什麼是攔截器呢?簡單點說就和埋點差很少。在請求的時候,會走每個攔截器!想添加什麼就添加什麼,這裏咱們經過幾個實例講解一下你就能大概理解了!
先看下代碼,而後我在作一下相應的解釋:
public class LogInterceptor implements Interceptor { private static final String TAG = LogInterceptor.class.getSimpleName(); @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); /*這樣就能在請求以前打印相應的內容了*/ Log.e("url", String.format("Sending request %s on %s %n %s", request.url(), chain.connection(), request.headers())); /*其實下面這個chain.proceed(request)這個方法,表明請求前和請求後*/ return chain.proceed(request); } } 複製代碼
這裏就是直接打印了一個相應的LOG,能夠獲取到一些請求的參數,這裏說明一下:
request.url()
的值了,飲後後面的headers獲取到的內容爲空,由於GET請求沒有相應的表單信息;chain.connection()
當你使用除了日誌攔截器的時候,就會返回空chain.proceed(request)
表明請求響應的結果,因此說明你也是能夠修改返回結果的!!!這個說來就有意思了,當你請求攔截器的時候,正常應該返回百度返回的內容,可是若是你修改了連接的地址會怎麼樣呢?固然就會返回你修改以後的返回地址了。。。咱們看看怎麼實現的
public class ResetInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request newRequest = new Request.Builder() .method("GET", null) .url("https://fanyi.baidu.com/translate?aldtype=16047&query=%E8%BF%9B%E5%BA%A6%0D%0A&keyfrom=baidu&smartresult=dict&lang=auto2zh#zh/en/%E9%87%8D%E7%BD%AE") .build(); return chain.proceed(newRequest); } } 複製代碼
對,你沒有看錯,就這麼赤裸裸的換了一個url地址,其實Request request = chain.request();
這個方法,返回的Request就是在建立的時候,建立的Request,因此,這裏你直接,經過攔截器,直接建立一個新的,直接返回就能夠了,就沒有以前的Request什麼事情了!!!其實就至關於你把以前的內容從新寫了一遍!就醬紫了。。。
其實這個的實現和上面的差很少,也就是替換相應的Request的內容!可是這裏你要考慮一個問題,就是GET請求和POST請求的處理方式應該是不一樣的,多以這裏要分狀況去處理。不然不能達到你想要的效果的!因此這裏咱們分開說。先說明一下,GET請求是在Url後面拼接相應的參數,而POST請求是在form表單中添加相應的參數,因此方式必定是不同的!!!
先來一段代碼體驗一下:
HttpUrl build = originalRequest.url().newBuilder() .addQueryParameter("key1", "value1") .addQueryParameter("key2", "value2") .addQueryParameter("key3", "value3") .addQueryParameter("key4", "value4") .addQueryParameter("key5", "value5") .build(); Request request = originalRequest.newBuilder().url(build).build(); 複製代碼
這樣就能夠添加相應的公共請求參數了,其實開始的時候,我覺得newBuilder()是建立一個新的內容呢?其實它是拿到以前的內容,而後把下面的內容添加進去。因此這裏其餘的內容是不會收到影響的!!!
其實GET請求就是在URL後面追加上相應的參數。
仍是先來一點代碼體驗一下:
Request requestBuilder = originalRequest.newBuilder() .addHeader("key1", "value1") .addHeader("key2", "value2") .addHeader("key3", "value3") .addHeader("key4", "value4") .addHeader("key5", "value5") .build(); 複製代碼
和上面的相似,只是寫法不一樣而已!由於POST請求添加的是相應的header。
總體的代碼以下:
public class PublicInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if ("GET".equals(request.method())) { //GET請求的處理 HttpUrl build = request.url().newBuilder() .addQueryParameter("key1", "value1") .addQueryParameter("key2", "value2") .addQueryParameter("key3", "value3") .addQueryParameter("key4", "value4") .addQueryParameter("key5", "value5") .build(); request = request.newBuilder().url(build).build(); } else if ("POST".equals(request.method())) { request = request.newBuilder() .addHeader("key1", "value1") .addHeader("key2", "value2") .addHeader("key3", "value3") .addHeader("key4", "value4") .addHeader("key5", "value5") .build(); } return chain.proceed(request); } } 複製代碼
最後在把相應的Interceptor添加到OkHttp就行了。
2018年10月15日補充:
在POST請求中,請求參數應該添加到body中,因此上面代碼是有問題的!
替換成下面這樣:
if (originalRequest.body() instanceof FormBody) { // 構造新的請求表單 FormBody.Builder builder = new FormBody.Builder(); FormBody body = (FormBody) originalRequest.body(); //將之前的參數添加 for (int i = 0; i < body.size(); i++) { builder.add(body.encodedName(i), body.encodedValue(i)); } //追加新的參數 builder.add("key1", "value1"); builder.add("key2", "value2"); builder.add("key3", "value3"); builder.add("key4", "value4"); builder.add("key5", "value5"); //構造新的請求體 originalRequest = originalRequest.newBuilder().post(builder.build()).build(); } 複製代碼
對於以上的錯誤深表歉意,由於沒有弄清楚http中的一下內容,還請見諒!!!
基本上使用的時候就這麼多問題,可能有些講解不到的,若是有什麼不到位的,及時補充!!!有問題留言,我看到了必定會回覆你的!!!