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 设置更多的参数,比如:header
、method
等;
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 中每次网络请求方式基本相似,因此对其进行一次封装,方便后续的开发与维护,框架类图如下:
其中,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 的网络框架。
- okHttp 基础及封装
- OkHttp的封装及使用方法
- okhttp简单封装及使用
- 网络请求封装及使用(okhttp)
- OkHttp使用及工具类封装
- OkHttp简单的封装及使用
- okhttp封装okhttp-utils
- 封装OKHttp
- 封装OkHttp
- okhttp封装
- 封装OKHttp
- 封装OKHttp
- Okhttp封装
- OkHttp 封装
- OkHttp封装
- OKHttp封装
- Okhttp封装
- okHttp封装
- 关于C语言中内存的3个问题
- 温补而知新——之(Android Studio 目录结构不同颜色代表意思)
- String类不可变性的好与坏
- Android 混淆从入门到精通
- #189. 转啊转
- okHttp 基础及封装
- 【CODEVS】树链剖分板子
- 无锁队列 lock free queue
- 无需序列化,复杂数据传递也如此简单,intent及进程间通信简化
- READING NOTE: DSSD: Deconvolutional Single Shot Detector
- Day01
- BFS(广搜)算法与模板 bfs求最短路
- 滚动条
- lantern官方下载