一,Okhttp优点
1,它会从很多常用的连接问题中自动回复
2,如果你的服务器配置了多个IP地址,当第一个IP连接失败的时候,Okhttp会自动尝试下一个IP.Android4.4版本开始,系统就内置了Okhttp.
二,基本使用
(一)添加依赖
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
(二)代码使用
1,简单封装,onResponse方法的回调并非在UI线程,所以要想更新UI,需要Handler将结果发送到UI线程
public class HappyOkhttpManager {
private static volatile HappyOkhttpManager instance;
private final OkHttpClient okHttpClient;
private static Handler handler;
private HappyOkhttpManager(Context context){
okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)//设置请求超时时间
.readTimeout(10, TimeUnit.SECONDS)//设置读取超时时间
.writeTimeout(10, TimeUnit.SECONDS)//设置写入超时时间
.build();
handler = new Handler(context.getMainLooper());
}
public static HappyOkhttpManager getInstance(Context context){
if (instance == null){
synchronized (HappyOkhttpManager.class){
if (instance == null){
instance = new HappyOkhttpManager(context.getApplicationContext());
}
}
}
return instance;
}
//mdiatype 这个需要和服务端保持一致
private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
public void postJson(String json, final HHttpStatus callBack ){
RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, json);
Request request = new Request.Builder()
.url(Constant.BASE_URL)
.post(body)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
errorCallBack(e.getMessage(),callBack);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// !!!! 判断response是否有对象 , 成功
if (response!=null&&response.isSuccessful()){
successCallBack(response.body().string(),callBack);
}else {
failCallBack(response.body().string(),callBack);
}
}
});
}
/**
* 统一同意处理成功信息
*
* @param result
* @param callBack
*/
private void successCallBack(final String result, final HHttpStatus callBack) {
handler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
callBack.onSuccess(result);
callBack.onFinish();
}
}
});
}
/**
* 统一处理失败信息
*
* @param
* @param callBack
*/
private void errorCallBack(final String exception, final HHttpStatus callBack) {
handler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
callBack.onException(exception);
callBack.onFinish();
}
}
});
}
/**
* 统一同意处理错误信息
*
* @param
* @param callBack
*/
private void failCallBack(final String errorMsg, final HHttpStatus callBack) {
handler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
callBack.onError(errorMsg);
callBack.onFinish();
}
}
});
}
}
//在activity中使用
sendHttpRequest(gainRequestJson());
private String gainRequestJson() {
return CreateNewJson.boxStateQueryBoxStateJson(shop_id, page + "", order + "", state, un_find_shopids, boxStateActivity);
}
HappyOkhttpManager.getInstance().postJson(httpJson, new HHttpStatus() {
@Override
public void onSuccess(String json) {
dissmisDialod(createLoadingDialog);
Log.e("date", "返回onResponse: "+json );
try {
JSONObject jsonObject = new JSONObject(json);
JSONObject response = jsonObject.getJSONObject("response");
String result_code = response.getString("result_code");
String error_msg = response.getString("error_msg");
if (result_code.equals("true")) {
activity.onSuccess(httpJson,json);
} else {
activity.onFail(httpJson,error_msg);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onError(String errorMsg) {
dissmisDialod(createLoadingDialog);
}
@Override
public void onException(String exception) {
dissmisDialod(createLoadingDialog);
if (exception.equals("java.net.SocketTimeoutException: timeout")) {
exception = activity.getString(R.string.net_overtime);
} else if (exception.contains("No address associated with hostname")) {
exception = "网络错误";
}else {
exception = activity.getString(R.string.server_error);
}
activity.onException(httpJson,exception);
}
@Override
public void onFinish() {
dissmisDialod(createLoadingDialog);
activity.onFinish();
}
});
}
三,源码解析
(一)newCall()处理请求
1,调用newCall()处理请求,实际上返回的是一个RealCall类,
@Override public Call newCall(Request request) {
return new RealCall(this, request);
}
2,我们调用的enqueue()其实是调用RealCall的enqueue(),最终的请求都是由Dispatch完成.
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
3,在Dispatch类中:
3.1,参数
public final class Dispatcher {
//最大并发请求数
private int maxRequests = 64;
//每个主机的最大请求数
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
//消费者线程池
private ExecutorService executorService;
//将要运行的异步请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在运行的异步请求队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在运行的同步请求队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
3.2,Dispatcher有2个构造,使用者可以自己设定线程池,如果使用者没有设定线程池,Dispatcher则会在请求网络钱创建默认的线程池.这个线程池类似于CachedThreadPool,比较适合执行大量的,耗时比较少的任务.
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
3.3,当正在运行的异步请求队列中的数量小于64,并且正在运行的请求主机数量小于5,就把请求添加到runningAsyncCalls(正在运行的异步请求队列)中,并执行.
否则,就加入到readyAsyncCalls(将要运行的异步请求队列)中进行缓存等待.
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
未完待续..............................
借鉴:
刘望舒先生的进阶之光