OkHttp使用详解
2016-12-18 18:04
190 查看
今天学习了一下
今天我们主要介绍
当然在开始之前,我们还要先在项目中添加
1 . 拿到OkHttpClient对象
2 . 构造Request对象
这里我们采用建造者模式和链式调用指明是进行Get请求,并传入Get请求的地址
如果我们需要在get请求时传递参数,我们可以以下面的方式将参数拼接在url之后
3 . 将Request封装为Call
4 . 根据需要调用同步或者异步请求方法
第四步有一些需要注意的地方
1. 同步调用会阻塞主线程,一般不适用
2. 异步调用的回调函数是在子线程,我们不能在子线程更新UI,需要借助于
是不是以为上面就结束了,对的,OkHttp的Get请求步骤就这么4步,但是当你试图打开应用加载数据,可是发现并没有加载到数据,这是一个简单但是我们常犯的错误.
在AndroidManifest.xml中加入联网权限
1 . 拿到OkHttpClient对象
2 . 构建FormBody,传入参数
3 . 构建Request,将FormBody作为Post方法的参数传入
4 . 将Request封装为Call
5 . 调用请求,重写回调方法
经过上面的步骤一个post请求就完成了,当然上面的
上面我们的post的参数是通过构造一个
上面的MediaType我们指定传输的是纯文本,而且编码方式是utf-8,通过上面的方式我们就可以向服务端发送json字符串啦。
注:关于MidiaType的类型你可以百度搜索
其实最主要的还是构架我们自己的
这里我们将手机SD卡根目录下的
注:最后记得最重要的一点:添加存储卡写权限,在
由于我们使用的是OkHttp3所以我们还需要再导入一个包
这里我们会用到一个
上面添加用户民和密码的部分和我们上面学习的提交键值对的方法很像,我们关键要注意以下几点:
(1)如果提交的是表单,一定要设置
(2)提交的文件
(3)提交的文件
(4)记得在
1 . 从网络下载一个文件(此处我们以下载一张图片为例)
你会发现步骤与进行一般的
2 . 从网络下载一张图片并设置到ImageView中
其实学会了上面的步骤你完全可以将图片下载到本地后再设置到ImageView中,当然下面是另一种方法
这里我们使用
1 . 显示文件下载进度
这里只是演示,我只是把进度显示在一个TextView中,至于进度的获取当然是在我们的回调函数
(1)使用
(2)在
2 . 显示文件上传进度
对于上传的进度的处理会比较麻烦,因为具体的上传过程是在
上面的代码注释非常详细,这里不再解释,然后我们在写具体的请求时还需要做如下变化
上面其实就是在原有的
OkHttp,在这里做个总结,希望可以帮助到有需要的人,好了,废话不多说,进入正题。
一、OkHttp介绍
OkHttp是一个优秀的网络请求框架,可能一说到网络请求框架,可能很多人都会想到volley,
volley是一个Google提供的网络请求框架,我的博客里也有一篇专门介绍
volley的博客,博客地址在此Volley的使用 那么既然Google提供了网络请求的框架,我们为什么还要使用
OkHttp呢,原来是
volley是要依靠
HttpCient的,而Google在
Android6.0的SDK中去掉了
HttpCient,所以
OkHttp就开始越来越受大家的欢迎.
今天我们主要介绍
OkHttp的
Get请求、
Post请求、
上传下载文件、
上传下载图片等功能。
当然在开始之前,我们还要先在项目中添加
OkHttp的依赖库,至于怎么在AndroidStudio中给项目添加OkHTTP依赖,这里将不再赘述。另外,OkHttp中使用了建造者模式,如果对建造者模式不了解,可以看看这篇博客设计模式之建造者模式
添加OkHttp的依赖
在对应的Module的gradle中添加 compile 'com.squareup.okhttp3:okhttp:3.5.0' 然后同步一下项目即可
二、OkHttp进行Get请求
使用OkHttp进行Get请求只需要四步即可完成。
1 . 拿到OkHttpClient对象
OkHttpClient client = new OkHttpClient();
2 . 构造Request对象
Request request = new Request.Builder() .get() .url("https://www.baidu.com") .build();
这里我们采用建造者模式和链式调用指明是进行Get请求,并传入Get请求的地址
如果我们需要在get请求时传递参数,我们可以以下面的方式将参数拼接在url之后
https:www.baidu.com?username=admin&password=admin
3 . 将Request封装为Call
Call call = client.newCall(request);
4 . 根据需要调用同步或者异步请求方法
//同步调用,返回Response,会抛出IO异常 Response response = call.execute(); //异步调用,并设置回调函数 call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Toast.makeText(OkHttpActivity.this, "get failed", Toast.LENGTH_SHORT).show(); } @Override public void onResponse(Call call, final Response response) throws IOException { final String res = response.body().string(); runOnUiThread(new Runnable() { @Override public void run() { contentTv.setText(res); } }); } });
第四步有一些需要注意的地方
1. 同步调用会阻塞主线程,一般不适用
2. 异步调用的回调函数是在子线程,我们不能在子线程更新UI,需要借助于
runOnUiThread()方法或者
Handler来处理
是不是以为上面就结束了,对的,OkHttp的Get请求步骤就这么4步,但是当你试图打开应用加载数据,可是发现并没有加载到数据,这是一个简单但是我们常犯的错误.
在AndroidManifest.xml中加入联网权限
<uses-permission android:name="android.permission.INTERNET" />
三、OkHttp进行Post请求提交键值对
使用OkHttp进行Post请求和进行
Get请求很类似,只需要五步即可完成。
1 . 拿到OkHttpClient对象
OkHttpClient client = new OkHttpClient();
2 . 构建FormBody,传入参数
FormBody formBody = new FormBody.Builder() .add("username", "admin") .add("password", "admin") .build();
3 . 构建Request,将FormBody作为Post方法的参数传入
final Request request = new Request.Builder() .url("http://www.jianshu.com/") .post(formBody) .build();
4 . 将Request封装为Call
Call call = client.newCall(request);
5 . 调用请求,重写回调方法
call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Toast.makeText(OkHttpActivity.this, "Post Failed", Toast.LENGTH_SHORT).show(); } @Override public void onResponse(Call call, Response response) throws IOException { final String res = response.body().string(); runOnUiThread(new Runnable() { @Override public void run() { contentTv.setText(res); } }); } });
经过上面的步骤一个post请求就完成了,当然上面的
url参数和需要传入的参数大家就要根据实际情况来传入,你会发现get和post请求的步骤非常像。
四、OkHttp进行Post请求提交字符串
如果你已经掌握了上面的两种基本的步骤,那下面的内容就比较简单了上面我们的post的参数是通过构造一个
FormBody通过键值对的方式来添加进去的,其实post方法需要传入的是一个
RequestBody对象,
FormBody是
RequestBody的子类,但有时候我们常常会遇到要传入一个字符串的需求,比如客户端给服务器发送一个json字符串,那这种时候就需要用到另一种方式来构造一个
RequestBody如下所示:
RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), "{username:admin;password:admin}");
上面的MediaType我们指定传输的是纯文本,而且编码方式是utf-8,通过上面的方式我们就可以向服务端发送json字符串啦。
注:关于MidiaType的类型你可以百度搜索
mime type查看相关的内容,这里不再赘述
五、OkHttp进行Post请求上传文件
理解了上面一个,下面这个就更简单了,这里我们以上传一张图片为例,当然你也可以上传一个txt什么的文件,都是可以的其实最主要的还是构架我们自己的
RequestBody,如下图构建
File file = new File(Environment.getExternalStorageDirectory(), "1.png"); if (!file.exists()){ Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show(); }else{ RequestBody requestBody2 = RequestBody.create(MediaType.parse("application/octet-stream"), file); }
这里我们将手机SD卡根目录下的
1.png图片进行上传。代码中的
application/octet-stream表示我们的文件是
任意二进制数据流,当然你也可以换成更具体的
image/png
注:最后记得最重要的一点:添加存储卡写权限,在
AndroidManifest.xml文件中添加如下代码:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
六、OkHttp进行Post请求提交表单
我们在网页上经常会遇到用户注册的情况,需要你输入用户名,密码,还有上传头像,这其实就是一个表单,那么接下来我们看看如何利用OkHttp来进行表单提交。经过上面的学习,大家肯定也懂,主要的区别就在于构造不同的RequestBody传递给
post方法即可.
由于我们使用的是OkHttp3所以我们还需要再导入一个包
okio.jar才能继续下面的内容,我们需要在模块的Gradle文件中添加如下代码,然后同步一下项目即可
compile 'com.squareup.okio:okio:1.11.0'
这里我们会用到一个
MuiltipartBody,这是
RequestBody的一个子类,我们提交表单就是利用这个类来构建一个
RequestBody,下面的代码我们会发送一个包含用户民、密码、头像的表单到服务端
File file = new File(Environment.getExternalStorageDirectory(), "1.png"); if (!file.exists()){ Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show(); return; } RequestBody muiltipartBody = new MultipartBody.Builder() //一定要设置这句 .setType(MultipartBody.FORM) .addFormDataPart("username", "admin")// .addFormDataPart("password", "admin")// .addFormDataPart("myfile", "1.png", RequestBody.create(MediaType.parse("application/octet-stream"), file)) .build();
上面添加用户民和密码的部分和我们上面学习的提交键值对的方法很像,我们关键要注意以下几点:
(1)如果提交的是表单,一定要设置
setType(MultipartBody.FORM)这一句
(2)提交的文件
addFormDataPart()的第一个参数,就上面代码中的
myfile就是类似于键值对的键,是供服务端使用的,就类似于网页表单里面的
name属性,例如下面:
<input type="file" name="myfile">
(3)提交的文件
addFormDataPart()的第二个参数文件的本地的名字,第三个参数是
RequestBody,里面包含了我们要上传的文件的路径以及
MidiaType
(4)记得在
AndroidManifest.xml文件中添加存储卡读写权限
七、OkHttp进行get请求下载文件
除了上面的功能,我们最常用的功能该有从网路上下载文件,我们下面的例子将演示下载一个文件存放在存储卡根目录,从网络下载一张图片并显示到ImageView中1 . 从网络下载一个文件(此处我们以下载一张图片为例)
public void downloadImg(View view){ OkHttpClient client = new OkHttpClient(); final Request request = new Request.Builder() .get() .url("https://www.baidu.com/img/bd_logo1.png") .build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e("moer", "onFailure: ");; } @Override public void onResponse(Call call, Response response) throws IOException { //拿到字节流 InputStream is = response.body().byteStream(); int len = 0; File file = new File(Environment.getExternalStorageDirectory(), "n.png"); FileOutputStream fos = new FileOutputStream(file); byte[] buf = new byte[128]; while ((len = is.read(buf)) != -1){ fos.write(buf, 0, len); } fos.flush(); //关闭流 fos.close(); is.close(); } }); }
你会发现步骤与进行一般的
Get请求差别不大,唯一的区别在于我们在回调函数中所做的事,我们拿到了图片的字节流,然后保存为了本地的一张图片
2 . 从网络下载一张图片并设置到ImageView中
其实学会了上面的步骤你完全可以将图片下载到本地后再设置到ImageView中,当然下面是另一种方法
这里我们使用
BitmapFactory的
decodeStream将图片的输入流直接转换为
Bitmap,然后设置到
ImageView中,下面只给出
onResponse()中的代码.
@Override public void onResponse(Call call, Response response) throws IOException { InputStream is = response.body().byteStream(); final Bitmap bitmap = BitmapFactory.decodeStream(is); runOnUiThread(new Runnable() { @Override public void run() { imageView.setImageBitmap(bitmap); } }); is.close(); }
八、给文件的上传和下载加上进度条
我们一直都说,用户体验很重要,当我们下载的文件比较大,而网速又比较慢的时候,如果我们只是在后台下载或上传,没有给用户显示一个进度,那将是非常差的用户体验,下面我们就将简单做一下进度的显示,其实非常简单的1 . 显示文件下载进度
这里只是演示,我只是把进度显示在一个TextView中,至于进度的获取当然是在我们的回调函数
onResponse()中去获取
(1)使用
response.body().contentLength()拿到文件总大小
(2)在
while循环中每次递增我们读取的buf的长度
@Override public void onResponse(Call call, Response response) throws IOException { InputStream is = response.body().byteStream(); long sum = 0L; //文件总大小 final long total = response.body().contentLength(); int len = 0; File file = new File(Environment.getExternalStorageDirectory(), "n.png"); FileOutputStream fos = new FileOutputStream(file); byte[] buf = new byte[128]; while ((len = is.read(buf)) != -1){ fos.write(buf, 0, len); //每次递增 sum += len; final long finalSum = sum; Log.d("xh1", "onResponse: " + finalSum + "/" + total); runOnUiThread(new Runnable() { @Override public void run() { //将进度设置到TextView中 contentTv.setText(finalSum + "/" + total); } }); } fos.flush(); fos.close(); is.close(); }
2 . 显示文件上传进度
对于上传的进度的处理会比较麻烦,因为具体的上传过程是在
RequestBody中由
OkHttp帮我们处理上传,而且
OkHttp并没有给我们提供上传进度的接口,这里我们的做法是自定义类继承
RequestBody,然后重写其中的方法,将其中的上传进度通过接口回调暴露出来供我们使用。
public class CountingRequestBody extends RequestBody { //实际起作用的RequestBody private RequestBody delegate; //回调监听 private Listener listener; private CountingSink countingSink; /** * 构造函数初始化成员变量 * @param delegate * @param listener */ public CountingRequestBody(RequestBody delegate, Listener listener){ this.delegate = delegate; this.listener = listener; } @Override public MediaType contentType() { return delegate.contentType(); } @Override public void writeTo(BufferedSink sink) throws IOException { countingSink = new CountingSink(sink); //将CountingSink转化为BufferedSink供writeTo()使用 BufferedSink bufferedSink = Okio.buffer(countingSink); delegate.writeTo(bufferedSink); bufferedSink.flush(); } protected final class CountingSink extends ForwardingSink{ private long byteWritten; public CountingSink(Sink delegate) { super(delegate); } /** * 上传时调用该方法,在其中调用回调函数将上传进度暴露出去,该方法提供了缓冲区的自己大小 * @param source * @param byteCount * @throws IOException */ @Override public void write(Buffer source, long byteCount) throws IOException { super.write(source, byteCount); byteWritten += byteCount; listener.onRequestProgress(byteWritten, contentLength()); } } /** * 返回文件总的字节大小 * 如果文件大小获取失败则返回-1 * @return */ @Override public long contentLength(){ try { return delegate.contentLength(); } catch (IOException e) { return -1; } } /** * 回调监听接口 */ public static interface Listener{ /** * 暴露出上传进度 * @param byteWritted 已经上传的字节大小 * @param contentLength 文件的总字节大小 */ void onRequestProgress(long byteWritted, long contentLength); } }
上面的代码注释非常详细,这里不再解释,然后我们在写具体的请求时还需要做如下变化
File file = new File(Environment.getExternalStorageDirectory(), "1.png"); if (!file.exists()){ Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show(); }else{ RequestBody requestBody2 = RequestBody.create(MediaType.parse("application/octet-stream"), file); }
//使用我们自己封装的类
CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody2, new CountingRequestBody.Listener() {
@Override
public void onRequestProgress(long byteWritted, long contentLength) {
//打印进度
Log.d("xh", "进度 :" + byteWritted + "/" + contentLength);
}
});
上面其实就是在原有的
RequestBody上包装了一层,最后在我们的使用中在
post()方法中传入我们的
CountingRequestBody对象即可。
九、后记
以上就是一些OkHttp常用的总结,希望可以帮助到需要的人
相关文章推荐
- OkHttp在Android中使用详解
- OkHttp使用详解——完全版
- OKHttp使用详解
- Android中okhttp3使用详解
- okhttp实战使用详解
- OkHttp使用方法详解
- Retrofit 2.0使用详解,配合OkHttp、Gson,Android最强网络请求框架
- OkHttp使用详解一
- okhttp的详解及其缓存的使用
- okhttp的使用及详解
- Retrofit 2.0使用详解,配合OkHttp、Gson,Android最强网络请求框架
- Okhttp使用详解
- OkHttp使用详解
- OkHttp3使用详解
- Android OkHttp的简单使用和封装详解
- OKHttp使用详解及源码解析
- Android OkHttp 网络请求 使用详解
- Android okhttp3的使用详解
- OkHttp使用详解
- OKHttp使用详解,步骤挺详细的,适合初学者使用!