如今基本上全部的網絡框架都採用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);
}
});
}
});
複製代碼
這裏要說明的就多了:網絡
當你的看到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中的一下內容,還請見諒!!!
基本上使用的時候就這麼多問題,可能有些講解不到的,若是有什麼不到位的,及時補充!!!有問題留言,我看到了必定會回覆你的!!!