簡介:OKHttp是一個Android當前最火的處理網(wǎng)絡(luò)請求第三方框架庫,由移動支付Square公司開源貢獻的。用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient)。
封裝
- 對第三方框架進行封裝,是為了達到對模塊項目的控制,已最小的代價替換框架,達到對項目的控制。
首先看一下OKHttp的使用
private static OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(new LoggingInterceptor())
.cache(new Cache(context.getExternalFilesDir("okhttp"),cacheSize)).build();
public static void getRequest(String url, final ResultListener<Object> listener) {
Request request = new Request.Builder().url(url).method("GET", null).build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
if (null != listener) {
listener.onFailure(e.getMessage());
}
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (null != listener) {
listener.onSuccess(response);
}
}
});
}
這種封裝成工具類的比完全沒有封裝的好了很多,但是還是存在一定的問題的。封裝成工具類的話,別人完全有權(quán)限訪問你這個工具類,他可以隨時修改你工具類里面的實現(xiàn),這給維護帶來了一定的成本。
再此之前,我們要先了解網(wǎng)絡(luò)請求哪些參數(shù)是必要的,哪些是非必要的
- 必要選項
- url,請求地址
- paramMap,請求參數(shù)
- IResponseCallback,請求結(jié)果回調(diào)
- 非必要選項
- context 通常是用來配置配置一些緩存等一些信息
- headMap 請求頭
- tag 請求 TAG,用來區(qū)分或者取消網(wǎng)絡(luò)請求
- connectTimeout 連接超時時間
- readTimeout 讀取超時時間
- writeTimeout 寫入超時時間
了解完必要參數(shù)和非必要參數(shù)之后,我們就將采用建造者模式,把非必要的參數(shù)都提取封裝在ManbaOkhttpOption當中。代碼如下:
public class ManbaOkhttpOption {
private String mUrl;
private String mTag;
private Map<String, String> mHeaders;
public ManbaOkhttpOption(String mTag) {
this.mTag = mTag;
}
public String getTag() {
return mTag;
}
public Map<String, String> getHeaders() {
return mHeaders;
}
public static final class Builder {
public String mTag;
public Map<String, String> mHeaders;
public String mUrl;
public Builder setTag(String mTag) {
this.mTag = mTag;
return this;
}
public Builder setHeaders(Map<String, String> mHeaders) {
this.mHeaders = mHeaders;
return this;
}
public Builder setUrl(String mUrl) {
this.mUrl = mUrl;
return this;
}
public ManbaOkhttpOption build() {
ManbaOkhttpOption option = new ManbaOkhttpOption(mTag);
option.mHeaders = mHeaders;
option.mUrl = mUrl;
return option;
}
}
}
建造者模式的優(yōu)點:
- 封裝性很好,將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,對外屏蔽了對象的構(gòu)建過程
- 擴展性強,如果有新的需求,只需要增加新的具體建造者,無須修改原有類庫的代碼
這樣封裝實現(xiàn)出來的接口IManbaRequest:
public interface IManbaRequest {
void init(Context context);
void doGet(String url, IResponseCallback callback);
void doGet(String url, Map<String, String> paramsMap, IResponseCallback callback);
void doGet(String url, Map<String, String> paramsMap, ManbaOkhttpOption option, IResponseCallback callback);
void doPost(String url, Map<String, String> paramsMap, IResponseCallback callback);
void doPost(String url, Map<String, String> paramsMap, ManbaOkhttpOption option, IResponseCallback callback);
void cancel(String tag);
}
可以看到,我們有幾個方法:
- init 方法,主要用來配置一些初始化參數(shù)
- doGet 有兩個方法,其中一個方法是另外一個方法的重載,這樣設(shè)計的目的是為了減少調(diào)用方法的時候減少方法參數(shù)的傳遞
- doPost 跟 doGet 方法一樣,就不說了
- cancel 主要是用來取消網(wǎng)絡(luò)請求的。在項目當中,在 Activity 或者 Fragment 銷毀的時候,最好取消網(wǎng)絡(luò)請求,不然可能導致內(nèi)存泄露或者異常,如空指針異常等。
ManbaOkhttpRequest實現(xiàn)
OkHttp 的配置是非常靈活的,這樣我們主要看一下怎么配置請求頭,請求參數(shù),以及怎樣取消網(wǎng)絡(luò)請求。
package com.sunhdj.manbaokhttp;
import android.content.Context;
import android.os.Handler;
import com.sunhdj.manbaokhttp.utils.NetUtils;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* huangdaju
* 2020-02-25
**/
public class ManbaOkhttpRequest implements IManbaRequest {
private static int cacheSize = 10 * 1024 * 1024; // 10 MiB
private static OkHttpClient client;
private Context mContext;
public static Handler mHandler = new Handler();
public static Handler getHandler() {
if (mHandler == null) {
mHandler = new Handler();
}
return mHandler;
}
private volatile static ManbaOkhttpRequest instance = null;
private ManbaOkhttpRequest() {
}
public static ManbaOkhttpRequest getInstance() {
if (null == instance) {
synchronized (ManbaOkhttpRequest.class) {
if (null == instance) {
instance = new ManbaOkhttpRequest();
}
}
}
return instance;
}
@Override
public void init(Context context) {
mContext = context.getApplicationContext();
client = getCilent();
}
private OkHttpClient getCilent() {
if (client == null) {
OkHttpClient.Builder mBuilder = new OkHttpClient.Builder().
connectTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(new LoggingInterceptor())
.cache(new Cache(mContext.getExternalFilesDir("manbaOkhttp"), cacheSize));
client = mBuilder.build();
}
return client;
}
@Override
public void doGet(String url, IResponseCallback callback) {
doGet(url, null, null, callback);
}
@Override
public void doGet(String url, Map<String, String> paramsMap, IResponseCallback callback) {
doGet(url, paramsMap, null, callback);
}
@Override
public void doGet(String url, Map<String, String> paramsMap, ManbaOkhttpOption option, final IResponseCallback callback) {
url = NetUtils.appendUrl(url, paramsMap);
final ManbaOkhttpOption manbaOkhttpOption = NetUtils.checkNetworkOption(option, url);
Request.Builder builder = new Request.Builder().url(url).tag(manbaOkhttpOption.getTag());
builder = configHeaders(builder, manbaOkhttpOption);
Request build = builder.build();
getCilent().newCall(build).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
handleError(e, callback);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
handleResult(response, callback);
}
});
}
@Override
public void doPost(String url, Map<String, String> paramsMap, IResponseCallback callback) {
doPost(url,paramsMap,null,callback);
}
@Override
public void doPost(String url, Map<String, String> paramsMap, ManbaOkhttpOption option, final IResponseCallback callback) {
url = NetUtils.appendUrl(url, paramsMap);
final ManbaOkhttpOption manbaOkhttpOption = NetUtils.checkNetworkOption(option, url);
// 以表單的形式提交
FormBody.Builder builder = new FormBody.Builder();
builder=configPostParam(builder,paramsMap);
FormBody formBody = builder.build();
Request.Builder requestBuilder = new Request.Builder().url(url).post(formBody).tag(manbaOkhttpOption.getTag());
requestBuilder = configHeaders(requestBuilder, manbaOkhttpOption);
Request build = requestBuilder.build();
getCilent().newCall(build).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
handleError(e, callback);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
handleResult(response, callback);
}
});
}
private FormBody.Builder configPostParam(FormBody.Builder builder, Map<String, String> paramsMap) {
if(paramsMap!=null){
Set<Map.Entry<String, String>> entries = paramsMap.entrySet();
for(Map.Entry<String,String> entry:entries ){
String key = entry.getKey();
String value = entry.getValue();
builder.add(key,value);
}
}
return builder;
}
private Request.Builder configHeaders(Request.Builder builder, ManbaOkhttpOption option) {
Map<String, String> headers = option.getHeaders();
if (headers == null || headers.size() == 0) {
return builder;
}
Set<Map.Entry<String, String>> entries = headers.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
builder.addHeader(key, value);
}
return builder;
}
private void handleResult(Response response, final IResponseCallback callback) throws IOException {
final String result = response.body().string();
if (callback != null) {
getHandler().post(new Runnable() {
@Override
public void run() {
callback.onResponse(result);
}
});
}
}
private void handleError(IOException e, final IResponseCallback callback) {
if (callback != null) {
final ManbaOkHttpException httpException = new ManbaOkHttpException();
httpException.e = e;
getHandler().post(new Runnable() {
@Override
public void run() {
callback.onFail(httpException);
}
});
}
}
@Override
public void cancel(String tag) {
if (client != null) {
for (Call call : client.dispatcher().queuedCalls()) {
if (call.request().tag().equals(tag)) {
call.cancel();
}
}
}
}
}
ManbaOkhttpRequest的實現(xiàn)其實很簡單,主要根據(jù)ManbaOkhttpOption做相應(yīng)的配置。如果不熟悉okhttp的request用法,請參考博客OkHttp使用完全教程。
每天多努力那么一點點,積少成多