1.寫在前面:
網絡請求架構層出不窮,像google的volley,xutils等等。聽說Okhttp性能很高,最近寫新項目,決定用Okhttp來嘗試一下(原諒我是小白,第一次使用,以前還是用volley),以此來記錄一下自己的心得。
2.首先來介紹一下Okhttp:
Okhttp出自鼎鼎大名的Square,官方github位址:https://github.com/square/okhttp;它基本包含所有常用的網絡請求,同步、異步的get、post請求,檔案上傳下載下傳等等,廢話不說,直接進入教程
3.Okhttp的使用:
1)首先添加依賴:
Download the latest JAR or grab via Maven:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.6.0</version>
</dependency>
or Gradle:
compile 'com.squareup.okhttp3:okhttp:3.6.0'
還在用eclipse的童鞋也可以下載下傳jar使用,不過抓緊時間換Android Studio吧;
2)同時别忘了添加添加網絡權限:
3)開始編寫代碼:
http同步get請求:
/**
* 同步的Get請求
*
* @param url
* @return responseStr
* @throws IOException
*/
public static String getSync(String url) throws IOException {
// 建立OKHttpClient對象
OkHttpClient okHttpClient = new OkHttpClient();
// 建立一個Request
final Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
// 傳回值為response
Response response = call.execute();
// 将response轉化成String
String responseStr = response.body().string();
return responseStr;
}
OKHttp請求成功的傳回值為Response ,一般可以通過response.body().string()擷取傳回的字元串;也可以通過response.body().bytes()擷取傳回的二進制位元組數組;也可以通過response.body().byteStream()擷取傳回的inputStream。
http異步get請求:
/**
* 異步的Get請求
*
* @param url url
*/
public static void getAsyn(String url) {
// 建立OKHttpClient對象
OkHttpClient okHttpClient = new OkHttpClient();
// 建立一個Request
final Request request = new Request.Builder()
.url(url)
.build();
Call call = okHttpClient.newCall(request);
// 請求加入排程
call.enqueue(new Callback() {
// 請求失敗的回調
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
// 請求成功的回調
@Override
public void onResponse(Call call, Response response) throws IOException {
// 将response轉化成String
String responseStr = response.body().string();
}
});
}
同上OKHttp請求成功的傳回值為Response ,一般可以通過response.body().string()擷取傳回的字元串;值得注意的是它的傳回值是在子線程中而不是UI線程,想要在UI線程中使用,還需要使用handler等,例如:
// 請求成功的回調
@Override
public void onResponse(Call call, Response response) throws IOException {
// 将response轉化成String
String responseStr = response.body().string();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), responseStr,
Toast.LENGTH_SHORT).show();
}
}
}
這樣http的異步get請求就完成了,如果每次請求都寫如此多的代碼而且傳回值還不是在UI線程,那每發送一次請求都很麻煩,看到這,你一定會想到封裝,沒錯,将OKHttp封裝成一個工具類,每次使用直接去調用就簡單多了,在本文最後我也會提供我自己對OKHttp的簡單封裝,供大家參考。
http同步post請求:
/**
* 同步的Post請求
*
* @param url url
* @param params params
* @return responseStr
* @throws IOException
*/
public static String postSync(String url, Map<String, String> params)
throws IOException {
// RequestBody
RequestBody requestBody;
if (params == null) {
params = new HashMap<>();
}
// 建立OKHttpClient對象
OkHttpClient okHttpClient = new OkHttpClient();
FormBody.Builder builder = new FormBody.Builder();
/**
* 在這對添加的參數進行周遊
*/
for (Map.Entry<String, String> map : params.entrySet()) {
String key = map.getKey();
String value;
/**
* 判斷值是否是空的
*/
if (map.getValue() == null) {
value = "";
} else {
value = map.getValue();
}
/**
* 把key和value添加到formBody中
*/
builder.add(key, value);
}
requestBody = builder.build();
// 建立一個Request
final Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
// 傳回值為response
Response response = call.execute();
// 将response轉化成String
String responseStr = response.body().string();
return responseStr;
}
大家知道,發送post請求時,參數是包含在請求體中的,是以我們去構造RequestBody,最後完成我們Request的構造。
http異步post請求:
/**
* 異步的Post請求
*
* @param url url
* @param params params
* @return responseStr
*/
public static void postAsyn(String url, Map<String, String> params) {
// RequestBody
RequestBody requestBody;
if (params == null) {
params = new HashMap<>();
}
// 建立OKHttpClient對象
OkHttpClient okHttpClient = new OkHttpClient();
FormBody.Builder builder = new FormBody.Builder();
/**
* 在這對添加的參數進行周遊
*/
for (Map.Entry<String, String> map : params.entrySet()) {
String key = map.getKey();
String value;
/**
* 判斷值是否是空的
*/
if (map.getValue() == null) {
value = "";
} else {
value = map.getValue();
}
/**
* 把key和value添加到formBody中
*/
builder.add(key, value);
}
requestBody = builder.build();
// 建立一個Request
final Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 将response轉化成String
String responseStr = response.body().string();
}
});
}
以上是基于http的異步post請求,上面的例子添加的請求參數是Map,當然也可以添加其他類型的參數,如:
// post傳參(byte)
RequestBody byteBody = RequestBody.create(MediaType.parse("application/octet-stream; charset=utf-8"), mapToBytes(params));
mapToBytes(params)方法是将params轉化成byte
http的檔案上傳:
/**
* 基于http的檔案上傳
* 通過addFormDataPart可以添加多個上傳的檔案
*/
public void uploadMultiFile() {
// 建立OKHttpClient對象
OkHttpClient okHttpClient = new OkHttpClient();
File file = new File(Environment.getExternalStorageDirectory(), "pic.png");
RequestBody fileBody = RequestBody.create
(MediaType.parse("application/octet-stream"), file);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("image", "pic.png", fileBody)
.build();
Request request = new Request.Builder()
.url("填寫url位址")
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}
http的檔案下載下傳:
/**
* 基于http的下載下傳檔案請求
*
* @param downloadUrl 下載下傳位址
*/
public static void downloadRequest(String downloadUrl) {
// 建立OKHttpClient對象
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(downloadUrl)
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 下載下傳成功後執行的操作
}
});
}
OKHttp的簡單封裝使用(NetRequest工具類):
以上是OKHttp常用的請求,其他請求類似,不再重複。下面對OKHttp進行簡單的封裝,使其使用友善,不必每次都寫大量的重複方法,同時直接将傳回值Response傳遞到UI線程,将其封裝在OKHttp的工具類中,簡化代碼,下面直接貼代碼:
package com.guifa.okhttpdemo.http;
import android.os.Handler;
import android.os.Looper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by GuiFa on 2017/2/3.
* 網絡請求工具類
*/
public class NetRequest {
private static NetRequest netRequest;
private static OkHttpClient okHttpClient; // OKHttp網絡請求
private Handler mHandler;
private NetRequest() {
// 初始化okhttp 建立一個OKHttpClient對象,一個app裡最好執行個體化一個此對象
okHttpClient = new OkHttpClient();
okHttpClient.newBuilder()
.connectTimeout(, TimeUnit.SECONDS)
.readTimeout(, TimeUnit.SECONDS)
.writeTimeout(, TimeUnit.SECONDS);
mHandler = new Handler(Looper.getMainLooper());
}
/**
* 單例模式 擷取NetRequest執行個體
*
* @return netRequest
*/
private static NetRequest getInstance() {
if (netRequest == null) {
netRequest = new NetRequest();
}
return netRequest;
}
//-------------對外提供的方法Start--------------------------------
/**
* 建立網絡架構,擷取網絡資料,異步get請求(Form)
*
* @param url url
* @param params key value
* @param callBack data
*/
public static void getFormRequest(String url, Map<String, String> params, DataCallBack callBack) {
getInstance().inner_getFormAsync(url, params, callBack);
}
/**
* 建立網絡架構,擷取網絡資料,異步post請求(Form)
*
* @param url url
* @param params key value
* @param callBack data
*/
public static void postFormRequest(String url, Map<String, String> params, DataCallBack callBack) {
getInstance().inner_postFormAsync(url, params, callBack);
}
/**
* 建立網絡架構,擷取網絡資料,異步post請求(json)
*
* @param url url
* @param params key value
* @param callBack data
*/
public static void postJsonRequest(String url, Map<String, String> params, DataCallBack callBack) {
getInstance().inner_postJsonAsync(url, params, callBack);
}
//-------------對外提供的方法End--------------------------------
/**
* 異步get請求(Form),内部實作方法
*
* @param url url
* @param params key value
*/
private void inner_getFormAsync(String url, Map<String, String> params, final DataCallBack callBack) {
if (params == null) {
params = new HashMap<>();
}
// 請求url(baseUrl+參數)
final String doUrl = urlJoint(url, params);
// 建立一個請求
final Request request = new Request.Builder().url(doUrl).build();
//執行請求獲得響應結果
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
deliverDataFailure(request, e, callBack);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) { // 請求成功
//執行請求成功的操作
String result = response.body().string();
deliverDataSuccess(result, callBack);
} else {
throw new IOException(response + "");
}
}
});
}
/**
* 異步post請求(Form),内部實作方法
*
* @param url url
* @param params params
* @param callBack callBack
*/
private void inner_postFormAsync(String url, Map<String, String> params, final DataCallBack callBack) {
RequestBody requestBody;
if (params == null) {
params = new HashMap<>();
}
FormBody.Builder builder = new FormBody.Builder();
/**
* 在這對添加的參數進行周遊
*/
for (Map.Entry<String, String> map : params.entrySet()) {
String key = map.getKey();
String value;
/**
* 判斷值是否是空的
*/
if (map.getValue() == null) {
value = "";
} else {
value = map.getValue();
}
/**
* 把key和value添加到formbody中
*/
builder.add(key, value);
}
requestBody = builder.build();
//結果傳回
final Request request = new Request.Builder().url(url).post(requestBody).build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
deliverDataFailure(request, e, callBack);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) { // 請求成功
//執行請求成功的操作
String result = response.body().string();
deliverDataSuccess(result, callBack);
} else {
throw new IOException(response + "");
}
}
});
}
/**
* post請求傳json
*
* @param url url
* @param callBack 成功或失敗回調
* @param params params
*/
private void inner_postJsonAsync(String url, Map<String, String> params,final DataCallBack callBack) {
// 将map轉換成json,需要引入Gson包
String mapToJson = new Gson().toJson(params);
final Request request = buildJsonPostRequest(url, mapToJson);
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
deliverDataFailure(request, e, callBack);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) { // 請求成功
//執行請求成功的操作
String result = response.body().string();
deliverDataSuccess(result, callBack);
} else {
throw new IOException(response + "");
}
}
});
}
/**
* Json_POST請求參數
*
* @param url url
* @param json json
* @return requestBody
*/
private Request buildJsonPostRequest(String url, String json) {
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
return new Request.Builder().url(url).post(requestBody).build();
}
/**
* 分發失敗的時候調用
*
* @param request request
* @param e e
* @param callBack callBack
*/
private void deliverDataFailure(final Request request, final IOException e, final DataCallBack callBack) {
/**
* 在這裡使用異步處理
*/
mHandler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
callBack.requestFailure(request, e);
}
}
});
}
/**
* 分發成功的時候調用
*
* @param result result
* @param callBack callBack
*/
private void deliverDataSuccess(final String result, final DataCallBack callBack) {
/**
* 在這裡使用異步線程處理
*/
mHandler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
try {
callBack.requestSuccess(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
/**
* 資料回調接口
*/
public interface DataCallBack {
void requestSuccess(String result) throws Exception;
void requestFailure(Request request, IOException e);
}
/**
* 拼接url和請求參數
*
* @param url url
* @param params key value
* @return String url
*/
private static String urlJoint(String url, Map<String, String> params) {
StringBuilder endUrl = new StringBuilder(url);
boolean isFirst = true;
Set<Map.Entry<String, String>> entrySet = params.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
if (isFirst && !url.contains("?")) {
isFirst = false;
endUrl.append("?");
} else {
endUrl.append("&");
}
endUrl.append(entry.getKey());
endUrl.append("=");
endUrl.append(entry.getValue());
}
return endUrl.toString();
}
}
NetRequest工具類的簡單使用:
String url = "網絡請求的位址";
HashMap<String, String> params = new HashMap<>();
// 添加請求參數
params.put("key", "value");
// ...
NetRequest.getFormRequest(url, params, new NetRequest.DataCallBack() {
@Override
public void requestSuccess(String result) throws Exception {
// 請求成功的回調
}
@Override
public void requestFailure(Request request, IOException e) {
// 請求失敗的回調
}
});
至于同步get、post請求同理,而且個人感覺使用較少,便沒有寫出,檔案下載下傳和上傳同理。以上便是我對OKHttp的使用和認識,當然OKHttp遠遠不止這些,以後再慢慢補充。以上均為個人觀點,如有錯誤,歡迎留言指出,以便及時修正。
