OKhttp的post请求和get请求
- 提交键值对
//1.创建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//2.通过new FormBody()调用build方法,创建一个RequestBody,可以用add添加键值对
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 = okHttpClient.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 {
}
});
- 提交字符串
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");//"类型,字节码"
//字符串
String value = "{username:admin;password:admin}";
//1.创建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//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 = okHttpClient.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请求上传文件
首先添加存储卡读写权限,在AndroidManifest.xml文件中添加如下代码:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
具体代码:
//1.创建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//上传的图片
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 = okHttpClient.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请求下载文件
//1.创建OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//2.创建Request对象,设置一个url地址(百度地址),设置请求方式。
Request request = new Request.Builder().url("https://www.baidu.com/img/bd_logo1.png").get().build();
//3.创建一个call对象,参数就是Request请求对象
Call call = okHttpClient.newCall(request);
//4.请求加入调度,重写回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "onFailure: "+call.toString() );
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//拿到字节流
InputStream is = response.body().byteStream();
int len = 0;
//设置下载图片存储路径和名称
File file = new File(Environment.getExternalStorageDirectory(),"baidu.png");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[128];
while((len = is.read(buf))!= -1){
fos.write(buf,0,len);
Log.e(TAG, "onResponse: "+len );
}
fos.flush();
fos.close();
is.close();
}
});
Get请求下载文件还是比较简单,设置下载地址,在回调函数中拿到了图片的字节流,然后保存为了本地的一张图片。
从网络下载一张图片并直接设置到ImageView中。
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream is = response.body().byteStream();
//使用 BitmapFactory 的 decodeStream 将图片的输入流直接转换为 Bitmap
final Bitmap bitmap = BitmapFactory.decodeStream(is);
//在主线程中操作UI
runOnUiThread(new Runnable() {
@Override
public void run() {
//然后将Bitmap设置到 ImageView 中
imageView.setImageBitmap(bitmap);
}
});
is.close();
}
OkHttp与http请求
http协议请求消息体分为4部分:请求行(请求方法、请求地址、请求协议)、请求头部、空行和请求数据。也就是说要完成http请求,需要包含请求方法、请求地址、请求协议、请求头、请求体五部分
public final class Request {
final HttpUrl url; //请求地址
final String method;//请求方法
final Headers headers;//请求头
final RequestBody body; //请求体
final Object tag;
...
}
注:没有请求协议,根据服务器支持哪种协议(Http/1.1 Http/2),就选择哪种协议(Upgrade 机制)
OkHttp与http响应
响应消息分为4部分:状态行(访问协议、响应码、描述信息)、响应头、空行和响应正文(响应体)
public final class Response implements Closeable {
final Request request; //持有的请求
final Protocol protocol; //请求协议
final int code; //响应码
final String message; //描述信息
final Handshake handshake;//代表SSL/TLS握手协议验证时的信息
final Headers headers;
final ResponseBody body; //响应体
final Response networkResponse;
final Response cacheResponse;
final Response priorResponse;
final long sentRequestAtMillis;
final long receivedResponseAtMillis;
...
}
注:response.body().string()只能调用一次,在第一次是有返回值,第二次调用就会返回null。原因:response.body().string()的本质是输入流的读操作,必须有服务器的输出流的写操作时客户端的读操作才能得到数据。而服务器的写操作只执行一次,所以客户端的读操作也只能执行一次,第二次将返回null。
单例的OKHttpClient会不会影响OkHttpClient的扩展性
不会,我们之所以要单例一个OKHttpClient,是应该不重复创建连接池和线程池
也就是说,可以全局定义一个OkHttpClient ,在需要特殊配置一个OKHttpClient的时候,这个局部的OKHttpClient
引用的连接池和线程池是复用自全局单例的就行;
如:
OkHttpClient eagerClient = client.newBuilder()
.readTimeout(500, TimeUnit.MILLISECONDS)
.build();
Response response = eagerClient.newCall(request).execute();
具体实现是:通过全局的OkHttpClient 单例new属性一样的的Builder,然后给这个Builder单独配置局部的属性
后,再通过这个Builder创建一个局部的OKHttpClient即可。
public Builder newBuilder() {
return new Builder(this);
}
Builder(OkHttpClient okHttpClient) {
this.dispatcher = okHttpClient.dispatcher;
this.proxy = okHttpClient.proxy;
//省略代码
}