okHttp 基础及封装

来源:互联网 发布:国家统计局gdp数据 编辑:程序博客网 时间:2024/04/30 22:28

okHttp 基础及封装

@(Android 学习)[okhttp, 网络]
[TOC]

Google 在 6.0 版本里面删除了 HttpClient 相关 API,OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。

OkHttp 官网
OkHttp 官方 API 文档
OkHttp GitHub 地址

1. 添加依赖

compile 'com.squareup.okhttp:okhttp:2.4.0'

因为 okhttp 内部依赖 okio,因此还需要导入 okio:

compile 'com.squareup.okio:okio:1.5.0'

2. 使用教程

2.1 Http Get

在网络请求中,最常见的就是 http get 请求,具体用法如下:
1. 首先构造一个 Request 对象,参数最起码要有个 url,也可以通过 Request.Builder 设置更多的参数,比如:headermethod等;
2. 通过 request 的对象构造一个 Call 对象,类似于将请求封装成任务;
3. 最后,以异步的方式去执行请求,调用call.enqueue,将 call 加入调度队列,然后等待任务执行完成,在 Callback 中即可得到结果。

// 创建 OKHttpClient 对象OkHttpClient mOkHttpClient = new OkHttpClient();// 创建一个 Requestfinal Request request = new Request.Builder().url("https://github.com/hongyangAndroid").build();// new callCall mCall = mOkHttpClient.newCall(request);// 请求加入调度mCall.enqueue(new Callback() {    @Override    public void onFailure(Request request, IOException e) {    }    @Override    public void onResponse(Response response) throws IOException {//                String htmlStr = response.body().string();    }});

onResponse 回调的参数是 response,一般情况下,如果希望获得返回的字符串,可以通过 response.body().string() 获取;如果希望获得返回的二进制字节数组,则调用 response.body().bytes();如果希望获得返回的 inputStream,则调用 response.body().byteStream()。
可以看到能够拿到返回的 inputStream,表明支持大文件下载,有 inputStream 就可以通过 IO 的方式写文件。这也说明一个问题,onResponse 执行的线程并不是 UI 线程,如果希望操作控件,就需要使用 handler,如:

Overridepublic void onResponse(Response response) throws IOException {    final String res = response.body().string();    runOnUiThread(new Runnable() {        @Override        public void run() {            mTv.setText(res);        }    });}

上面的是用异步的方式去执行,也支持阻塞的方式,就是调用 Call.execute() 方法,也同样返回一个 Response。


2.2 Http Post 携带参数

Post 方法中,整体用法跟 Get 方法相似,只是 Request 的构造不同。Post 的参数是包含在请求体中的,所以通过 FormEncodingBuilder 添加多个 String 键值对,然后构造 RequestBody,完成 Request 的构造:

FormEncodingBuilder builder = new FormEncodingBuilder();builder.add("username", "Savage_Lin");Request request = new Request.Builder().url(url).post(builder.build()).build();mOkHttpClient.newCall(request).enqueue(new Callback() {});

2.3 基于 Http 的文件上传

当需要类似表单上传的时候,可以使用 MultipartBuilder 来构造 RequestBody 实现。

File file = new File(Environment.getExternalStorageDirectory(), "balabala.mp4");RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"),        file);RequestBody requestBody = new MultipartBuilder().type(MultipartBuilder.FORM).addPart        (Headers.of("Content-Disposition", "form-data: name \"username\""), RequestBody                .create(null, "Savage-Lin")).addPart(Headers.of("Content-Disposition",        "form-data: name=\"mFile\"; filename=\"wjd.mp4\""), fileBody).build();Request request = new Request.Builder().url("server url").post(requestBody).build();Call call = mOkHttpClient.newCall(request);call.enqueue(new Callback() {    // ...});

上述代码向服务器传递了一个键值对 username:Savage-Lin 和一个文件。通过 MultipartBuilder 的 addPart 方法添加键值对或文件。
这里类似于凭借模拟浏览器行为的方式,详细可参考HTTP 网络请求原理。
图片下载是通过回调的 Response 拿到 byte[] 然后 decode 成图片;文件下载是拿到 inputStream 做写文件操作,关于用法,可以参考泡网OkHttp使用教程。


3. 对基本请求的封装

因为 okhttp 中每次网络请求方式基本相似,因此对其进行一次封装,方便后续的开发与维护,框架类图如下:


@Android 网络框架类图

其中,BasicHttp 类封装了基本的网络请求参数以及网络请求抽象方法,LSHttp 类通过 SubAPI 类中传递过来的参数,实现了具体的网络请求方法,发起具体的网络请求;BasicAPI 类封装发起网络请求所需的参数以及网络请求回调方法,LSAPI 类相当于 API 类的中间类,封装了同一类业务中相同的请求参数以及请求操作,具体的参数设置以及具体的回调方法在 SubAPI 类中实现。

3.1 BasicHttp 类

BasicHttp 类是一个抽象类,封装了网络请求所需的基本参数及配置,代码如下:

public abstract class BasicHttp implements Callback {    public BasicAPI basicAPI;    public String url;    public Headers headers;    public RequestBody requestBody;    // 创建一个 OkHttp 的请求对象    public Request request;    public Request.Builder requestBuilder = new Request.Builder();    public BasicHttp(BasicAPI basicAPI) {        this.basicAPI = basicAPI;    }    /**     * 配置请求 URL 地址     */    public abstract void setURL();    /**     * 添加请求头部     */    public abstract void setHeaders();    /**     * 添加请求参数     */    public abstract void setParams();    /**     * 配置 Request     */    public abstract void setRequest();    public void request() {        setURL();        setHeaders();        setRequest();        // 将请求加入请求队列        App.getOkHttpClientInstance().newCall(request).enqueue(this);    }}

OkHttp官方文档并不建议我们创建多个 OkHttpClient,因此全局使用一个(如果有需要,可以使用 clone 方法,再进行自定义),在 App 类中实例化后调用,同时实现 Callback 接口用于处理请求回调。
LSHttp 类继承了 BasicHttp 类,实现了对 Request 参数的设置。代码如下:

public class LSHttp extends BasicHttp {    private LSAPI api;    // 创建一个 FormEncodingBuilder 对象,用于存放表单中的 item    public FormEncodingBuilder bodyBuilder = new FormEncodingBuilder();    public LSHttp(LSAPI api) {        super(api);        this.api = api;    }    @Override    public void setURL() {        if (api.getMethod() == RequestMethod.GET) {            // if method is GET            String param = "?";            try {                for (Map.Entry<String, String> entry :                        api.getParams().entrySet()) {                    param += entry.getKey() + "=" + entry.getValue() + "&";                }                url = api.getUrl() + param;            } catch (Exception e) {                url = api.getUrl();            }        } else {            // if method is OTHER            url = api.getUrl();        }    }    @Override    public void setHeaders() {        headers = Headers.of(api.getHeaders());    }    @Override    public void setParams() {        for (Map.Entry<String, String> entry : api.getParams().entrySet()) {            bodyBuilder.add(entry.getKey(), entry.getValue());        }        requestBody = bodyBuilder.build();    }    @Override    public void setRequest() {        if (api.getMethod().equals(RequestMethod.GET)) {            requestBody = null;        } else {            setParams();        }        String method = api.getMethod().getMethod();        request = requestBuilder.url(url).headers(headers).method(method, requestBody).build();    }    @Override    public void onFailure(Request request, IOException e) {        api.requestFailure(600L, "服务繁忙,请稍后再试");    }    @Override    public void onResponse(Response response) throws IOException {        JSONObject jsonResponse;        if (response == null) {            api.requestFailure(600L, "response null");            return;        } else {            try {                jsonResponse = new JSONObject(response.body().string());            } catch (JSONException e) {                e.printStackTrace();                jsonResponse = new JSONObject();            }        }        // 判断服务器是否返回请求数据        boolean status = false;        long code = -1;        String msg = null;        try {            if (jsonResponse.has("status") && jsonResponse.has("code")) {                status = jsonResponse.getBoolean("status");                code = jsonResponse.getLong("code");                if (jsonResponse.has("msg")) {                    msg = jsonResponse.getString("msg");                }            }        } catch (JSONException e) {            e.printStackTrace();        }        if (200L == code && status) {            // 请求成功            JSONObject data;            try {                data = jsonResponse.getJSONObject("data");                api.requestSuccess(data, msg);            } catch (JSONException e) {                e.printStackTrace();            }        } else {            // 请求失败            api.requestFailure(600L, "request error");        }    }}

若是 GET 请求,则将参数拼接到 URL 中,同时将 requestBody 赋值为 null,若是其他请求,则将参数封装到 requestBody 中。同时对请求结果进行初次处理,若请求成功,且服务器返回的数据为 JSON 类型,如下:

<!--服务器返回的数据如下:-->{"status":true,"code":200,"data":{"result":{"method":"put","param":"good!"}}}

解析出 data 中的数据,交由 API 类处理。不解析到 result 字段是因为服务器返回来的数据可能是一个 JSONObject 对象,也有可能是一个 JSONArray 数据,还有可能就是一个字段,因此解析到 data。
BasicAPI 类和 LSAPI 类封装了 Request 中所需参数的 getter/setter 方法以及对返回数据的处理抽象方法。具体的业务 API 类只需实现 getUrl()、getMethod()、success()、error()方法即可,如下:

public class HelloAPI extends LSAPI {    public HelloAPI() {        addParam("param", "hello");        new LSHttp(this).request();    }    @Override    public String getUrl() {        return "http://api.6shangwang.com/region/app/v2/region/orgin";    }    @Override    public void success(JSONObject data, String msg) throws Exception {        Log.e("HelloAPI success", data.toString());    }    @Override    public void error(Long code, String msg) {        Log.e("HelloAPI error", msg);    }    @Override    public RequestMethod getMethod() {        return RequestMethod.POST;    }}

在需要发送该网络请求时,只需一行代码即可发送该网络请求:

new HelloAPI();

4. 对文件上传/下载的封装




以上,即是对 OkHttp 框架的简单介绍以及 Android 整合 OkHttp 的网络框架。


|center

0 0
原创粉丝点击