OKhttp在Androlua中的初级应用
HTTP是现代应用常用的一种交换数据和媒体的网络方式,高效地使用HTTP能让资源加载更快,节省带宽。
OkHttp是一个高效的HTTP客户端,它有以下默认特性:
- 支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
- 连接池减少请求延时
- 透明的GZIP压缩减少响应数据的大小
- 缓存响应内容,避免一些完全重复的请求
当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接,当握手失败时会回退到TLS 1.0。
OkHttp 支持 Android 2.3 及以上版本Android平台, 对于 Java, JDK 1.7及以上.
官方仓库地址
https://github.com/square/okhttp
DEX下载
Okhttp · 洛樱/STUDYuseto - 码云 - 开源中国 (gitee.com)
请求示例
异步GET请求
导入OKhttp库
-new OkHttpClient;
-构造Request对象;
-通过前两步中的对象构建Call对象;
-通过Call#enqueue(Callback)方法来提交异步请求;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| require "import" import "android.app.*" import "android.os.*" import "android.widget.*" import "android.view.*"
import "okhttp3.*"
request = Request.Builder() .url("http://www.baidu.com/") .build();
client = OkHttpClient() callz = client.newCall(request) callz.enqueue(Callback{ onFailure=function(call,e) end,
onResponse=function(call,response) end })
|
异步发起的请求会被加入到 Dispatcher
中的 runningAsyncCalls
双端队列中,该请求是否可以立即发起受 maxRequests 和 maxRequestsPerHost 两个条件的限制。如果符合条件,那么就会从 readyAsyncCalls 取出并存到 runningAsyncCalls 中,然后交由 OkHttp 内部的线程池来执行。
同步GET请求
前面几个步骤和异步方式一样,只是最后一部是通过 Call#execute()
来提交请求,注意这种方式会阻塞调用线程,所以在Android中应放在子线程中执行,否则有可能引起ANR异常,Android3.0
以后已经不允许在主线程访问网络,网络请求过程就会直接在调用者所在线程上完成,不受 Dispatcher 的控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| require "import" import "android.app.*" import "android.os.*" import "android.widget.*" import "android.view.*"
import "okhttp3.*"
request = Request.Builder() .url("http://www.baidu.com/") .build();
client = OkHttpClient() callz = client.newCall(request) callz.execute(Callback{ onFailure=function(call,e) end,
onResponse=function(call,response) end })
|
POST方式提交String
与前面的区别就是在构造Request对象时,需要多构造一个RequestBody对象,用它来携带我们要提交的数据。在构造 RequestBody
需要指定MediaType
,用于描述请求/响应 body
的内容类型,关于 MediaType
的更多信息可以查看 RFC 2045
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import 'com.kn.okhttp.*' import 'okhttp3.*'
mediaType = MediaType.parse('text/x-markdown; charset=utf-8')
requestBody = '114514' request = Request.Builder() .url('https://api.github.com/markdown/raw') .post(RequestBody.create(mediaType,requestBody)) .build()
okHttpClient = OkHttpClient() okHttpClient.newCall(request).enqueue(Callback{ onFailure = function(call,e) print(e) end, onResponse = function(call,response) headers = response.headers() print(headers) print(response.body().string()) end })
|
POST方式提交文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import 'com.kn.okhttp.*' import 'okhttp3.*'
mediaType = MediaType.parse("text/x-markdown; charset=utf-8"); okHttpClient = OkHttpClient(); file = File(activity.getLuaDir()..'/init.lua');
request = Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(mediaType, file)) .build();
okHttpClient.newCall(request).enqueue(Callback { onFailure = function(call, e) print(e) end,
onResponse = function(call,response) print(response.headers()) print(response.body().string()) end });
|
POST方式提交表单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import 'com.kn.okhttp.*' import 'okhttp3.*' okHttpClient = OkHttpClient(); requestBody = FormBody.Builder() .add("keyword", "114514") .build();
request = Request.Builder() .url("https://gitee.com/luo-ying2020/studyuseto") .post(requestBody) .build();
okHttpClient.newCall(request).enqueue(Callback { onFailure = function(call, e) print(e); end, onResponse = function(call, response) print(response.headers()) print(response.body().string()) end });
|
图床实战
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import 'com.kn.okhttp.*' import 'okhttp3.*'
import "android.content.Intent" local intent= Intent(Intent.ACTION_PICK) intent.setType("image/*") this.startActivityForResult(intent, 1)
function onActivityResult(requestCode,resultCode,intent) if intent then local cursor =this.getContentResolver ().query(intent.getData(), nil, nil, nil, nil) cursor.moveToFirst() import "android.provider.MediaStore" local idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA) fileSrc = cursor.getString(idx) filename = fileSrc:match('.+%/(.+)')
requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart('smfile',filename,RequestBody.create(MediaType.parse('multipart/form-data'),File(fileSrc))) .build() request = Request.Builder() .header('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36') .url('https://sm.ms/api/upload') .post(requestBody) .build() okHttpClient = OkHttpClient() okHttpClient.newCall(request).enqueue(Callback{ onFailure = function(call,e) print(e) end,
onResponse = function(call,response) headers = response.headers() print(headers) print(response.body().string()) end }) end end
|
主流程源码分析
指路
Okhttp3源码分析 - 简书 (jianshu.com)
Android知名三方库OKHttp(二) - 手写简易版 - 简书 (jianshu.com)
OkHttp3架构分析
指路
OkHttp3架构分析 - 简书 (jianshu.com)
三方库源码笔记(11)-OkHttp 源码详解 - 简书 (jianshu.com)
编码处理-应对GB2312的办法
1 2
| print(String(response.body().bytes(),"gb2312"))
|
OKhttp优缺点
优点
支持SPDY, 可以合并多个到同一个主机的请求。
使用连接池技术减少请求的延迟(如果SPDY是可用的话) 。
使用GZIP压缩减少传输的数据量,避免重复的网络请求、拦截器等等。
缺点
第一缺点是回调需要切到主线程,主线程要自己去写,还有就是传入调用比较复杂。
和线程一挂钩就很难用
参考 摘录
Okhttp3基本使用 - 简书
代码手册APP–AndroluaBox
nirenr写的代码
Okhttp3基本使用 - 简书