OkHttp3.x解析(一) OkHttp介绍以及基本使用

OkHttp是一个目前流行高效的HTTP客户端:

  • HTTP/2支持允许对同一主机的所有请求共享一个套接字。
  • 连接池减少了请求延迟(如果HTTP/2不可用)。
  • 透明的GZIP压缩了下载文件的大小。
  • 响应缓存完全避免了网络中的重复请求。

当网络出现问题的时候OkHttp依然坚守自己的职责,当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接,当握手失败时会回退到TLS 1.0。

OkHttp目前支持 Android 5.0 及以上版本Android平台, 对于 Java, JDK 1.7及以上.

但是不排除有部分低版本忠实粉丝,升级困难综合征晚期患者,因此:

The OkHttp 3.12.x branch supports Android 2.3+ (API level 9+) and Java 7+. These
 platforms lack support for TLS 1.2 and should not be used. But because upgrading 
 is difficult we will backport critical fixes to the 3.12.x branch through 
 December 31, 2021.
相关依赖库导入:
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
另外还需要导入一个内部依赖库:
implementation 'com.squareup.okio:okio:2.2.2'
相关库GitHub地址

OkHttp

OkIo
Okio这个库的功能从字面意思上理解就是处理IO操作的(OkHttp字面意思不也是处理http操作的么),具体原理细节后面单开章节再表。

友情提示记得添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>

下面开始介绍常用的几个请求的使用方法。
创建一个代理类:

public class OkHttpProxy {
    private static OkHttpProxy instance = null;
//   创建OkHttpClient对象
    private OkHttpClient client;
    private OkHttpProxy() {
          client = new OkHttpClient.Builder()
          .callTimeout(6000, TimeUnit.MILLISECONDS)
          .connectTimeout(6000, TimeUnit.MILLISECONDS)
          .readTimeout(20000, TimeUnit.MILLISECONDS)
          .writeTimeout(20000, TimeUnit.MILLISECONDS)
          .build();
    }
    public static OkHttpProxy getInstance() {
        synchronized (OkHttpProxy.class) {
            if (instance == null) {
                instance = new OkHttpProxy();
            }
        }
        return instance;
    }
}

1.同步Get请求

首先创建get方式的 Request对象:

    /**
     * 获取 get方式 Request 对象
     *
     * @param reqName 接口名称
     * @param param   参数
     * @return Request 对象
     */
    private Request getRequest(String reqName, Map<String, String> param) {
//        创建Request对象,设置一个url地址,设置请求方式。
        Request.Builder reqBuild = new Request.Builder();
        HttpUrl.Builder urlBuilder = HttpUrl.parse(BASE_URL + reqName)
                .newBuilder();
        for (Map.Entry<String, String> entry : param.entrySet()) {
            urlBuilder.addQueryParameter(entry.getKey(), entry.getValue());
        }
        return reqBuild.url(urlBuilder.build()).get().build();
    }

然后创建一个call对象,并使用同步方法发起请求:

    /**
     * 同步请求
     *
     * @param method       请求方式  get or post
     * @param reqName      接口名称
     * @param param        参数
     * @param callResponse 请求回调
     */
    public void execute(String method, String reqName, Map<String, String> param, final CallResponse callResponse) {
        final Call call = client.newCall("get".equals(method)?getRequest(reqName, param):postRequest(reqName,param));
        //同步调用会阻塞主线程,这边在子线程进行,这里就直接使用线程了,如果项目中使用最好是用线程池
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response response = call.execute();
                    callResponse(response, callResponse);
                } catch (Exception e) {
                    e.printStackTrace();
                    if (callResponse != null) {
                        callResponse.error(e);
                    }
                }
            }
        }).start();
    }
    /**
     * 处理请求结果
     *
     * @param response     请求结果
     * @param callResponse 回调接口对象
     * @throws IOException
     */
    private void callResponse(Response response, CallResponse callResponse) throws IOException {
        String body = response.body().string();
        if (!TextUtils.isEmpty(body)) {
            ResponseData responseData = JSONObject.parseObject(body, ResponseData.class);
            if ("success".equals(responseData.getType())) {
                callResponse.success(responseData.getList());
            } else {
                callResponse.fail(responseData.getMsg());
            }
        } else {
            callResponse.fail("请求失败");
        }
    }

最后调用接口:

        ApiWork.getInstance().getinfolist("1", "10", new CallResponse() {
            @Override
            public void success(final String data) {
            		//这里必须在主线程中更新UI,可以可以使用Handler
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            tvTitle.setText(data);
                        }
                    });
            }

            @Override
            public void fail(String msg) {
                Log.v("userlogin",msg);
            }

            @Override
            public void error(Exception e) {

            }
        });
2.异步Get请求

异步get请求只是在发起请求那与同步有区别,之前的步骤都一致:

/**
     * 异步请求
     *
     * @param method       请求方式  get or post
     * @param reqName      接口名称
     * @param param        参数
     * @param callResponse 请求回调
     */
    public void enqueue(String method, String reqName, Map<String, String> param, final CallResponse callResponse) {
        final Call call = client.newCall("get".equals(method) ? getRequest(reqName, param) : postRequest(reqName, param));
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                if (callResponse != null) {
                    callResponse.error(e);
                }
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                callResponse(response, callResponse);
            }
        });
    }
3.同步Post请求

在OkHttp中用Post方法向服务器发送一个请求体时,请求体需要是一个RequestBody。这个请求体可以是:

  • key-value:键值对类型
  • String:字符串类型
  • Form:类似于Html的表单数据提交
  • Stream:流类型
  • File:文件类型

在这里针对第一种方式做说明。

首先创建post方式的Request对象:

    /**
     * 获取 post方式 Request 对象
     *
     * @param reqName 接口名称
     * @param param   参数
     * @return Request 对象
     */
    private Request postRequest(String reqName, Map<String, String> param) {
//        创建Request对象,设置一个url地址,设置请求方式。
        FormBody.Builder mBuild = new FormBody.Builder();
        for (Map.Entry<String, String> entry : param.entrySet()) {
            mBuild.add(entry.getKey(), entry.getValue());
        }
        RequestBody requestBody = mBuild.build();
        return new Request.Builder()
                .url(BASE_URL + reqName)
                .post(requestBody)
                .build();
    }

然后创建一个call对象,并使用同步方法发起请求:

    /**
     * 同步请求
     *
     * @param method       请求方式  get or post
     * @param reqName      接口名称
     * @param param        参数
     * @param callResponse 请求回调
     */
    public void execute(String method, String reqName, Map<String, String> param, final CallResponse callResponse) {
        final Call call = client.newCall("get".equals(method) ? getRequest(reqName, param) : postRequest(reqName, param));
        //同步调用会阻塞主线程,这边在子线程进行,这里就直接使用线程了,如果项目中使用最好是用线程池
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response response = call.execute();
                    callResponse(response, callResponse);
                } catch (Exception e) {
                    e.printStackTrace();
                    if (callResponse != null) {
                        callResponse.error(e);
                    }
                }
            }
        }).start();
    }

请求数据方式跟get一样,参考get的写法。

4.异步Post请求

异步post请求只是在发起请求那与同步有区别,之前的步骤都一致:

    /**
     * 异步请求
     *
     * @param method       请求方式  get or post
     * @param reqName      接口名称
     * @param param        参数
     * @param callResponse 请求回调
     */
    public void enqueue(String method, String reqName, Map<String, String> param, final CallResponse callResponse) {
        final Call call = client.newCall("get".equals(method) ? getRequest(reqName, param) : postRequest(reqName, param));
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                if (callResponse != null) {
                    callResponse.error(e);
                }
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                callResponse(response, callResponse);
            }
        });
    }

数据回调接口:

public interface CallResponse {
    /**
     * 接口请求成功
     */
    void success(String data);

    /**
     * 接口请求失败
     */
    void fail(String msg);

    /**
     * 接口请求报错
     */
    void error(Exception e);

}

ApiWork 数据接口请求类:

public class ApiWork {
    private static ApiWork instance = null;
    private ApiWork() {
    }
    public static ApiWork getInstance() {
        synchronized (ApiWork.class) {
            if (instance == null) {
                instance = new ApiWork();
            }
        }
        return instance;
    }

    public void getinfolist(String nowpage,String pagesize,CallResponse callResponse){
        Map<String,String> param=new HashMap<>(2);
        param.put("nowpage",nowpage);
        param.put("pagesize",pagesize);
        OkHttpProxy.getInstance().execute("get","info/testokhttp",param,callResponse);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章