OkHttp的优点
- 支持HTTP2/SPDY(SPDY是Google开发的基于TCP的传输层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。)
- socket自动选择最好路线,并支持自动重连,拥有自动维护的socket连接池,减少3 握手次数,减少了请求延迟,共享Socket,减少对服务器的请求次数。
- 基于Headers的缓存策略减少重复的网络请求。
- 拥有Interceptors轻松处理请求与响应(自动处理GZip压缩
基本使用
- 添加依赖
compile 'com.squareup.okhttp3:okhttp:3.7.0'
compile 'com.squareup.okio:okio:1.12.0'
- 添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
- 发送一个请求一般需要五步
1 创建一个OkHttpClient对象,可以设置,超时时间,拦截器等
OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.addNetworkInterceptor(logInterceptor)
.build();
2 创建一个Request对象,通常设置:url,请求方法,设置请求头等,如果是post方法,还需要构建一个RequestBody,上传文件,字符串,表单等都需要通过不同的RequestBody去构建
Request request = new Request.Builder()
.url(url)
.post(RequestBody)
.build();
3 通过OkHttpClient和Request获取一个Call对象,Call对象有execute()和cancel()等方法
Call call = mOkHttpClient.newCall(request);
4 执行请求,可以异步请求,也可以同步请求
//同步请求
Response execute = call.execute();
//异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
5 处理结果
onResponse回调有一个参数是response,
如果我们想获得返回的是字符串,可以通过response.body().string()获取;
如果希望获得返回的二进制字节数组,则调用response.body().bytes();
如果你想拿到返回的inputStream,则调response.body().byteStream(),有inputStream我们就可以通过IO的方式写文件
打印完整的okhttp网络请求和响应消息
我们请求网络一般都需要拿到我们发送的参数和返回的参数,来确认问题,拿到这些的参数,需要三部
- 添加依赖
implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
- 继承拦截器
public class HttpLogger implements HttpLoggingInterceptor.Logger {
@Override
public void log(String message) {
Log.d("mmmhttp", message);
}
}
- 设置拦截器
HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(new HttpLogger());
logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.addNetworkInterceptor(logInterceptor)
.build();
通过上方三部就可以拿到对应的参数了
07-18 14:18:55.016 6391-6413/com.baidu.bpit.aibaidu.cachevoice D/mmmhttp: --> GET http://tts.baidu.com/text2audio?idx=1&tex=%E5%9B%BD%E5%BA%86%E8%8A%82%E5%BF%AB%E4%B9%90&cuid=xieyan&cod=2&lan=zh&ctp=1&pdt=1&pit=9 http/1.1
Host: tts.baidu.com
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.7.0
--> END GET
07-18 14:18:55.073 6391-6413/com.baidu.bpit.aibaidu.cachevoice D/mmmhttp: <-- 200 OK http://tts.baidu.com/text2audio?idx=1&tex=%E5%9B%BD%E5%BA%86%E8%8A%82%E5%BF%AB%E4%B9%90&cuid=xieyan&cod=2&lan=zh&ctp=1&pdt=1&pit=9 (56ms)
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Cache-Control: max-age=36000
Connection: keep-alive
Content-Length: 3456
Content-Type: audio/mp3
Date: Thu, 18 Jul 2019 06:18:54 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: nginx/1.8.0
Set-Cookie: BAIDUID=913C2C4A2038EC7D9B22A8FC7AC3AD53:FG=1; expires=Fri, 17-Jul-20 06:18:54 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1
07-18 14:18:55.074 6391-6413/com.baidu.bpit.aibaidu.cachevoice D/mmmhttp: <-- END HTTP (binary 3456-byte body omitted)
异步Get请求
省略了创建OkHttpClient的步骤,因为跟上方一样
//2.创建Request对象,设置一个url地址(百度地址),设置请求方式。
Request request = new Request.Builder()
.url("http://www.baidu.com")
.get()
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
Post提交键值对
RequestBody requestBody = new FormBody.Builder()
.add("name","zhangqilu")
.add("age","25").build();
//3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
Request request = new Request.Builder()
.url("url")
.post(requestBody)
.build();
//4.创建一个call对象,参数就是Request请求对象
Call call = mOkHttpClient.newCall(request);
//5.请求加入调度,重写回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
这是一个post方法,需要构建一个ReqestBody,这里由于要传入key-value,使用的是FormBody是RequestBody子类
POST请求提交字符串
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");//"类型,字节码"
//字符串
String value = "{username:admin;password:admin}";
//2.通过RequestBody.create 创建requestBody对象
RequestBody requestBody =RequestBody.create(mediaType, value);
//3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
Request request = new Request.Builder()
.url("url")
.post(requestBody)
.build();
//4.创建一个call对象,参数就是Request请求对象
Call call = mOkHttpClient.newCall(request);
//5.请求加入调度,重写回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
POST请求上传文件
//上传的图片
File file = new File(Environment.getExternalStorageDirectory(), "zhuangqilu.png");
//2.通过RequestBody.create 创建requestBody对象,application/octet-stream 表示文件是任意二进制数据流
RequestBody requestBody =RequestBody.create(MediaType.parse("application/octet-stream"), file);
//3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
Request request = new Request.Builder()
.url("url")
.post(requestBody)
.build();
//4.创建一个call对象,参数就是Request请求对象
Call call = mOkHttpClient.newCall(request);
//5.请求加入调度,重写回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
GET请求下载文件
//2.创建Request对象,设置一个url地址(百度地址),设置请求方式。
Request request = new Request.Builder()
.url(url)
.get()
.build();
//3.创建一个call对象,参数就是Request请求对象
Call call = mOkHttpClient.newCall(request);
//4.请求加入调度,重写回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("mmm", "onFailure: " + call.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//拿到字节流
InputStream is = response.body().byteStream();
Log.d("mmm数据", is.available() + "/");
int len = 0;
//设置下载图片存储路径和名称
File file = new File(yunyinDir, name + ".mp3");
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[128];
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
Log.d("mmm", "onResponse: " + len);
}
Log.d("mmm", "下载完毕");
fos.flush();
fos.close();
is.close();
}
});
POST请求上传Multipart文件
有时候我们需要同时上传文件和其他类型字段,这其实就是一个表单,这里我们用MuiltipartBody来构建,他是RequestBody的一个子类
//上传的图片
File file = new File(Environment.getExternalStorageDirectory(), "zhuangqilu.png");
//2.通过new MultipartBody build() 创建requestBody对象,
RequestBody requestBody = new MultipartBody.Builder()
//设置类型是表单
.setType(MultipartBody.FORM)
//添加数据
.addFormDataPart("username","zhangqilu")
.addFormDataPart("age","25")
.addFormDataPart("image","zhangqilu.png", RequestBody.create(MediaType.parse("image/png"),file))
.build();
//3.创建Request对象,设置URL地址,将RequestBody作为post方法的参数传入
Request request = new Request.Builder().url("url").post(requestBody).build();
//4.创建一个call对象,参数就是Request请求对象
Call call = mOkHttpClient.newCall(request);
//5.请求加入调度,重写回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
参考:https://blog.csdn.net/zhangqiluGrubby/article/details/71480546