1.介紹
OkHttp是由Square公司開發的一個用於Android和Java的HTTP/HTTP2的網絡請求庫,它的一些優點:
- 在HTTP2的支持下,如果請求的host是同一個時,允許這些請求共用一個socket
- 使用連接池減少網絡延遲,如果HTTP2不可用
- 透明的GZIP壓縮,減少數據流量
- 緩存網絡響應,避免重複網絡請求
除此之外,還可以自動從常見網絡錯誤中恢復過來。如果服務器有多個IP地址,當第一次連接失敗,會自動重試其他IP地址。請求和響應使用建造者模式,使用簡便。
GitHub地址爲 https://github.com/square/okhttp
2.使用
添加依賴
implementation("com.squareup.okhttp3:okhttp:4.2.2")
2.1 GET同步請求
調用execute()
方法執行同步請求
private void loadDataSync() {
new Thread(new Runnable() {
@Override
public void run() {
String url = "http://publicobject.com/helloworld.txt";
//構建一個GET請求
Request request = new Request.Builder().get().url(url).build();
//創建一個OkHttpClient
OkHttpClient okHttpClient = new OkHttpClient();
try {
//執行請求獲取結果
Response response = okHttpClient.newCall(request).execute();
//得到響應字符串
String string = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
2.2 GET異步請求
調用enqueue()
方法執行異步請求,請求會在內部的線程池進行,請求結果通過回調Callback返回,回調方法都在子線程執行,所以不能直接更新ui。
private void loadDataAsync() {
String url = "http://publicobject.com/helloworld.txt";
Request request = new Request.Builder().get().url(url).build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
//在子線程中回調
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
//獲取字節數組
byte[] bytes = response.body().bytes();
//獲取InputStream
InputStream inputStream = response.body().byteStream();
}
});
}
另外response.body().string()
方法只能調用一次,這只因爲第一次調用string()時會關閉I/O流並清空Buffer,這樣做是爲了防止無用的,多的I/O操作。可以看一下方法的源碼
public final String string() throws IOException {
try (BufferedSource source = source()) {
Charset charset = Util.bomAwareCharset(source, charset());
return source.readString(charset);
}
}
2.3 POST提交表單
使用FromBody.Builder構建一個提交表單的請求體,添加鍵值對。
private void postForm() {
OkHttpClient client = new OkHttpClient();
//創建提交表單的請求體,添加鍵值對
RequestBody formBody = new FormBody.Builder()
.add("search", "Uncle")
.build();
//創建POST請求
Request request = new Request.Builder()
.url("https://en.wikipedia.org/w/index.php")
.post(formBody)
.build();
//異步請求
client.newCall(request).enqueue(mPostFormCallback);
}
private Callback mPostFormCallback = new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//獲取返回的HTML字符串
final String result = response.body().string();
runOnUiThread(new Runnable() {
@Override
public void run() {
//使用webView加載
//mWebView.loadData(result, "text/html", "utf-8");
}
});
}
};
2.4 POST提交JSON
只需要創建請求體時指定媒體類型爲"application/json"即可
private void postJson() {
String json = "";
String url = "";
OkHttpClient okHttpClient = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
RequestBody requestBody = RequestBody.create(mediaType, json);
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(mPostFormCallback);
}
2.5 緩存
緩存的配置只需要在創建OkHttp時傳入一個Cache,指定緩存目錄和大小即可。
int cacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(cacheDir, cacheSize);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(cache)
.build();
3 攔截器
攔截器機制能夠監控、重寫、重試請求。根據攔截的位置可分2種,一種是應用攔截器,攔截應用層與OkHttp之間的網絡請求和響應;另一種是網絡攔截器,攔截OkHttp與網絡層之間的網絡請求和響應。
定義一個攔截器LoggingInterceptor
,在攔截方法intercept中,獲取網絡請求。
public class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
//獲取請求
Request request = chain.request();
long t1 = System.nanoTime();
//打印請求的url,連接,請求頭
Log.d("TAG", "sending request: " +
request.url() + chain.connection() + request.headers());
//執行請求,返回結果
Response response = chain.proceed(request);
long t2 = System.nanoTime();
//打印執行請求的url,響應頭,消耗時間
Log.d("TAG", "received response: " +
response.request().url() + response.headers() + (t2 - t1));
return response;
}
}
然後將這個攔截器設置爲應用攔截器,通過addInterceptor
方法將攔截器設置給OkHttpClient。
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
使用addNetworkInterceptor
設置網絡攔截器
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(new LoggingInterceptor())
.build();
攔截器可以添加移除或者替換網絡請求和響應頭裏面的字段,同時也可以加工請求體和響應體,比如當返回網絡響應時,在響應頭裏並沒有配置Cache-Control來控制緩存,但我們又想讓這個響應緩存起來,這時可以配置一下網絡攔截器攔截網絡響應,在響應頭裏添加這個字段。
private static final Interceptor REWERITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
CacheControl.Builder builder = new CacheControl.Builder()
.maxAge(5, TimeUnit.MINUTES);
return originalResponse.newBuilder()
.header("Cache-Control", builder.build().toString())
.build();
}
};