面试题之---Okhttp源码解析

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_38859786/article/details/80308065

一,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);
  }
}

未完待续..............................

 

借鉴:

刘望舒先生的进阶之光

展开阅读全文

没有更多推荐了,返回首页