Android 网络申请之 OKHttp3
OKHttp 是一个第三方类库,用于 Android 申请网络,这是一个开源我的项目是 Android 最炽热的轻量
一:援用
implementation 'com.squareup.okhttp3:okhttp:3.8.0'//OKHttp3 网络申请框架
implementation 'com.squareup.okio:okio:1.12.0'//Android OKHttp3 应用须要增加一个收入 IO 的 okio 包
二:一个简略的 okhttp 应用
// 第一步:构建者模式,创立实例
OkHttpClient mClient=new OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)// 设置连贯超时 20s
.build();
// 第二步, 构建者模式,创立申请信息
Request mRequest=new Request.Builder()
.get()
.url("https://www.baidu.com")
.build();
// 第三步, 将 request 转成 call
Call call=mClient.newCall(mRequest);
// 第四步,执行 call 申请的, 异步
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) { }
@Override
public void onResponse(Call call, Response response) throws IOException {if (response.isSuccessful()){
// 响应胜利后, 拿到响应体
final String body= response.body().string();
// 切换回主线程等
runOnUiThread(new Runnable() {
@Override
public void run() {// 主线程}
});
}
}
});
这样的话,咱们只能相当于应用的是异步的 get 申请,还有同步申请,以及 post 申请,等等,故咱们须要对其进行封装
下面创立 OkHttp 只是一个简略的,还有其余属性
final Dispatcher dispatcher;// 调度器
final Proxy proxy;// 代理
final List<Protocol> protocols;// 协定
final List<ConnectionSpec> connectionSpecs;// 传输层版本和连贯协定
final List<Interceptor> interceptors;// 拦截器
final List<Interceptor> networkInterceptors;// 网络拦截器
final EventListener.Factory eventListenerFactory;
final ProxySelector proxySelector;// 代理选择器
final CookieJar cookieJar;//cookie
final Cache cache;//cache 缓存
final InternalCache internalCache;// 外部缓存
final SocketFactory socketFactory;//socket 工厂
final SSLSocketFactory sslSocketFactory;// 安全套层 socket 工厂 用于 https
final CertificateChainCleaner certificateChainCleaner;// 验证确认响应书,实用 HTTPS 申请连贯的主机名
final HostnameVerifier hostnameVerifier;// 主机名字确认
final CertificatePinner certificatePinner;// 证书链
final Authenticator proxyAuthenticator;// 代理身份验证
final Authenticator authenticator;// 本地省份验证
final ConnectionPool connectionPool;// 链接池 复用连贯
final Dns dns; // 域名
final boolean followSslRedirects;// 安全套接层重定向
final boolean followRedirects;// 本地重定向
final boolean retryOnConnectionFailure;// 重试连贯失败
final int connectTimeout;// 连贯超时
final int readTimeout;// 读取超时
final int writeTimeout;// 写入超时
第 1 步就是用构建者模式创立 okhttp3 的实例,外面封装了一些应用中必要的属性,如超时工夫,拦截器等
OKhttp 拦截器是一种弱小的机制,能够监督,重写和重试 Call 申请
Okhttp 中拦截器分 2 个 APP 层面的拦截器和网络申请层面的拦截器
Application Interceptor:
不须要放心是否影响 OKHttp 的申请策略和申请速度
即便从缓存中取数据,也会执行 Application 拦截器
容许重试,即 Chain.proceed()能够执行屡次。
能够监听察看这个申请的最原始的未扭转的用意 (申请头,申请体等),无奈操作 OKHttp 为咱们主动增加额定的申请头
无奈操作两头的响应后果,比方当 URL 重定向产生以及申请重试,只能操作客户端被动第一次申请以及最终的响应后果
Network Interceptors
能够批改 OkHttp 框架主动增加的一些属性,即容许操作两头响应,比方当申请操作产生重定向或者重试等。
能够察看最终残缺的申请参数(也就是最终服务器接管到的申请数据和相熟)
// 利用拦截器
Interceptor appInterceptor=new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
// get token
String token = AppService.getToken();
Request originalRequest = chain.request();
// get new request, add request header
Request updateRequest = originalRequest.newBuilder()
.header("token", token)
.build();
Response response = chain.proceed(updateRequest);// 申请
Log.d("TAG", "app intercept:end");
return response ;
}
};
/**
* 网络拦截器
*/
Interceptor networkInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {Request request = chain.request();
Log.d(TAG,"network interceptor:begin");
Response response = chain.proceed(request);// 申请
Log.d(TAG,"network interceptor:end");
return response;
}
};
// 应用
okHttpClient = new OkHttpClient
.Builder()
.addInterceptor(appInterceptor)
.addNetworkInterceptor(networkInterceptor)
.build();
三:Request 的创立
final HttpUrl url; // 接口地址
final String method; // post 还是 get
final Headers headers; // Http 音讯的头字段
final RequestBody body; // 它是抽象类,有些申请须要咱们传入 body 实例,如果是 GET 申请,body 对象传的是 null,如果是 POST 申请,就须要咱们去设定了。final Object tag;
第 2 步就是用构建者模式创立申请信息的实例,外面封装了一些应用中必要的属性,如申请形式,申请头信息,接口地址等
四:Call 对象的创立
@Override public Call newCall(Request request) {return new RealCall(this, request, false /* for web socket */);
}
第 3 步就是创立 realcall 对象,真正的申请是交给了 RealCall 类,它实现了 Call 办法,它是真正的外围代码。
五:realcall 的异步申请
// 调用
`call.enqueue(new Callback(){...});`
// 源码
@Override
public void enqueue(Callback responseCallback) {1.synchronized (this) {if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
2.client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
synchronized (this) 确保每个 call 只能被执行一次不能反复执行,如果想要完全相同的 call,能够调用如下办法:进行克隆
利用 dispatcher 调度器,来进行理论的执行 client.dispatcher().enqueue(new AsyncCall(responseCallback)), 这里分为 2 步走
// 看一下 new AsyncCall(responseCallback)
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
}
总结一下
在 call.enqueue(new Callback(){…}) 执行之后,首先做的是
- 调用 RealCall.call.enqueue()办法,判断以后 call 是否曾经被执行过了,被执行过了,就抛出异样,如果没有执行过,就先将 callback 封装成 AsyncCall,而后调用 dispatcher.enqueue()办法(dispatcher 调度器,在 okHttpClient 外面创立的)
- 在 dispatcher.enqueue()办法中,判断以后正在执行的申请数及以后网络申请的主机数是否超过了最大值。要是超过了最大值,就将申请放到期待队列中,要是没超过,就放当正在执行的队列中,而后调用线程池执行它。
四:相干封装实例
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(10, TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS);
//Handler 线程
mHandler=new Handler(Looper.getMainLooper());
}
/**
* 单例模式获取 NetRequest 实例 */
private static NetRequest getInstance(){if (netRequest==null){netRequest=new NetRequest();
}
return netRequest;
}
//
/**
* 建设网络框架,获取网络数据,异步 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);
}
/**
* 异步 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();}
}
END: 用于实际,基于原理