今天总结下OKhttp3框架的一些功能,其实现在很多可能不直接用okhttp3了,用的是retrofit,它其实并不是一个网络框架,而是对okhttp3进行了更好的封装,方便调用,底层网络这块用的还是okhttp3,所以又必要学习下okhttp3的使用。
okhttp3功能很丰富,有同步,异步,文件下载,上传,请求头,cookie等一系列
同步请求
关于请求的一些什么超时等,都是封装在OkHttpClient类中,这是一个全局的发送请求的,okhttp3框架中所有的请求,都是封装在Request中,包括请求方式,请求添加url,请求添加头部信息,请求设置相关tag,这是和取消请求有关系.Request中使用了Builder模式,
Request request = new Request.Builder() .url(url) .get() .addHeader("aa","aa") .build();其实一个Request请求封装了,okhttp3包括了所有的请求方式
public Builder get() { return method("GET", null); } public Builder head() { return method("HEAD", null); } public Builder post(RequestBody body) { return method("POST", body); } public Builder delete(@Nullable RequestBody body) { return method("DELETE", body); } public Builder delete() { return delete(Util.EMPTY_REQUEST); } public Builder put(RequestBody body) { return method("PUT", body); } public Builder patch(RequestBody body) { return method("PATCH", body); }现在我们发送一个get同步请求:
String url = "https://www.baidu.com/"; OkHttpClient okHttpClient = new OkHttpClient(); Request request = new Request.Builder() .url(url) .get() .build(); Call call = okHttpClient.newCall(request); try { Response response = call.execute(); if(null!=response&&response.isSuccessful()&&response.code()==200){ Log.e(TAG,"content="+response.body().string()); } } catch (IOException e) { e.printStackTrace(); }发现报错了:
Caused by: android.os.NetworkOnMainThreadException
这是说在4.0以后不能在主线程中发送网络请求,所以我们要开启一个子线程中发送了,
结果:
结果是请求ok了,但是我们其实实际开发中很少用到同步请求了,大部分都用是异步,
异步请求
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url("https://www.baidu.com/").build(); client.newCall(request).enqueue(new Callback(){ @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { if(null!=response&&response.isSuccessful()){ Log.e(TAG,"content="+response.body().string()); } } });
okhttp3请求返回不是说给我们返回一个string字符串,因为你下载返回肯定不是一个string啊,看下response.body()返回有那么值就知道了:
如果是下载文件就是返回一个byte[] 或者byteStream流,如果是一个普通的请求就返回一个string了,后面会整合Gson,封装一个工具类,可以直接使用,把json转成一个Model给上层调用.
下面讲的都是以异步请求为主,这些都是不带请求参数的,那么如果带请求参数的怎么传递参数呢?异步请求带参数
OkHttpClient client = new OkHttpClient(); HttpUrl httpUrl = HttpUrl.parse("http://bz.budejie.com/?typeid=2&ver=3.4.3&no_cry=1&client=android&c=wallPaper&a=wallPaperNew&index=1&size=60&bigid=0").newBuilder().addQueryParameter("name","zhouguizhi").build(); Request request = new Request.Builder().url(httpUrl).get().build(); client.newCall(request).enqueue(new Callback(){ @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { if(null!=response&&response.isSuccessful()){ Log.e(TAG,"content="+response.body().string()); } } });上面的url地址,是我在网上随便找了一个地址,就带了一个请求参数name,请求返回log:
11-24 00:42:58.899 14125-14525/com.simple E/MainActivity: content={"code":"E00000000","msg":"\u64cd\u4f5c\u6210\u529f\u3002","data":{"TotalCount":"80089","WallpaperListInfo":[{"ID":10983957,"PicName":"10983957.jpg","pic_path":"\/picture1\/M00\/0E\/8B\/wKiFQ1Osx3GAOttdAAF3dCmTv6k397.jpg","BigCategoryId":1040,"SecondCategoryId":2132,"CreateTime":"2014-06-27 09:21:24","passtime":"2016-06-05 11:54:49","UserName":"sprit_admin","DownloadCount":2721,"GoodCount":2730,"tags":"\u7238\u7238\u56de\u6765\u4e86","WallPaperMiddle":"http:\/\/bzpic.spriteapp.cn\/250x445\/picture1\/M00\/0E\/8B\/wKiFQ1Osx3GAOttdAAF3dCmTv6k397.jpg","WallPaperBig":"http:\/\/bzpic.spriteapp.cn\/1080x1920\/picture1\/M00\/0E\/8B\/wKiFQ1Osx3GAOttdAAF3dCmTv6k397.jpg","WallPaperDownloadPath":"http:\/\/bzpic.spriteapp.cn\/1080x1920\/picture1\/M00\/0E\/8B\/wKiFQ1Osx3GAOttdAAF3dCmTv6k397.jpg","WallPaperSource":"http:\/\/bzpic.spriteapp.cn\/744x1392\/picture1\/M00\/0E\/8B\/wKiFQ1Osx3GAOttdAAF3dCmTv6k397.jpg","weixin_url":"http:\/\/www.budejie.com\/bz\/bdj-10983957.html?wx.qq.com"},{"ID":10984612,"PicName":"10984612.jpg","pic_path":"\/picture1\/M00\/0E\/AA\/wKiFR1O08hCAfBH0AAK8jGL8Pi4655.jpg","BigCategoryId":1040,"SecondCategoryId":2629,"CreateTime":"2014-07-03 14:00:59","passtime":"2016-06-05 11:52:31","UserName":"173694","DownloadCount":2750,"GoodCount":2760,"tags":"\u5e05\u54e5 \u674e\u79c0\u8d6b \u674e\u8d6b\u79c0","WallPaperMiddle":"http:\/\/bzpic.spriteapp.cn\/250x445\/picture1\/M00\/0E\/AA\/wKiFR1O08hCAfBH0AAK8jGL8Pi4655.jpg","WallPaperBig":"http:\/\/bzpic.spriteapp.cn\/1080x1920\/picture1\/M00\/0E\/AA\/wKiFR1O08hCAfBH0AAK8jGL8Pi4655.jpg","WallPaperDownloadPath":"http:\/\/bzpic.spriteapp.cn\/1080x1920\/picture1\/M00\/0E\/AA\/wKiFR1O08hCAfBH0AAK8jGL8Pi4655.jpg","WallPaperSource":"http:\/\/bzpic.spriteapp.cn\/744x1392\/picture1\/M00\/0E\/AA\/wKiFR1O08hCAfBH0AAK8jGL8Pi4655.jpg","weixin_url":"http:\/\/www.budejie.com\/bz\/bdj-10984612.html?wx.qq.com"},{"ID":10781820,"PicName":"10781820.jpg","pic_path":"\/picture2\/M00\/07\/2E\/wKiFRlNYdQCAA5KFAAIX6TJTu3w941.jpg","BigCategoryId":1040,"SecondCategoryId":2629,"CreateTime":"2014-04-24 10:17:05","passtime":"2016-06-05 11:45:47","UserName":"135514","DownloadCount":2755,"GoodCount":2772,"tags":"\u5e05\u54e5","WallPaperMiddle":"http:\/\/bzpic.spriteapp.cn\/250x445\/picture2\/M00\/07\/2E\/wKiFRlNYdQCAA5KFAAIX6TJTu3w941.jpg","WallPaperBig":"http:\/\/bzpic.spriteapp.cn\/1080x1920\/picture2\/M00\/07\/2E\/wKiFRlNYdQCAA5KFAAIX6TJTu3w941.jpg","WallPaperDownloadPath":"http:\/\/bzpic.spriteapp.cn\/1080x1920\/picture2\/M00\/07\/2E\/wKiFRlNYdQCAA5KFAAIX6TJTu3w941.jpg","WallPaperSource":"http:\/\/bzpic.spriteapp.cn\/744x1392\/picture2\/M00\/07\/2E\/wKiFRlNYdQCAA5KFAAIX6TJTu3w941.jpg","weixin_url":"http:\/\/www.budejie.com\/bz\/bdj-10781820.html?wx.qq.com"},{"ID":10983477,"PicName":"10983477.jpg","pic_path":"\/picture2\/M00\/0A\/34\/wKiFWVOnjOKAG256AAF-TNkxjfk670.jpg","BigCategoryId":1056,"SecondCategoryId":2779,"CreateTime":"2014-06-23 10:10:01","passtime":"2016-06-05 11:42:20","UserName":"168844","DownloadCount":11359,"GoodCount":11369,"tags":"MYOTEE \u840c\u8138\u5c0f\u6484","WallPaperMiddle":"http:\/\/bzpic.spriteapp.cn\/250x445\/picture2\/M00\/0A\/34\/wKiFWVOnjOKAG256AAF-TNkxjfk670.jpg","WallPaperBig":"http:\/\/bzpic.spriteapp.cn\/1080x1920\/picture2\/M00\/0A\/34\/wKiFWVOnjOKAG256AAF-TNkxjfk670.jpg","WallPaperDownloadPath":"http:\/\/bzpic.spriteapp.cn\/1080x1920\/picture2\/M00\/0A\/34\/wKiFWVOnjOKAG256AAF-TNkxjfk670.jpg","WallPaperSource":"http:\/\/bzpic.spriteapp.cn\/744x1392\/picture2\/M00\/0A\/34\/wKiFWVOnjOKAG256AAF-TNkxjfk670.jpg","weixin_url":"http:\/\/www.budejie.com\/bz\/bdj-10983477.html?wx.qq.com"},{"ID":10984404,"PicName":"10984404.jpg","pic_path":"\/picture2\/M00\/0A\/63\/wKiFWVOzZ2mAbBJMAAOejEuFIXI097.jpg","BigCategoryId":1040,"SecondCategoryId":2624,"CreateTime":"2014-07-02 09:57:01","passtime":"2016-06-05 11:41:49","UserName":"73706","DownloadCount":10111,"GoodCount":10128,"tags":"\u674e\u51b0\u51b0 \u7f8e\u5973","WallPaperMiddle":"http:\/\/bzpic.spriteapp.cn\/250x445\/picture2\/M00\/0A\/63\/wKiFWVOzZ2mAbBJMAAOejEuFIXI097.jpg","WallPaperBi
这是返回的json,太长了,你发现其实json返回还不完整.但是请求是成功的,知道了get异步请求带参数就行
Post请求
OkHttpClient client = new OkHttpClient(); RequestBody formBody = new FormBody.Builder() .add("name", "zgz") .add("time",""+System.currentTimeMillis()) .add("id","1") .build(); Request request = new Request.Builder().url("http://zhushou.72g.com/app/gift/gift_list/").post(formBody).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG,"请求失败="+e); } @Override public void onResponse(Call call, Response response) throws IOException { if(null!=response&&response.isSuccessful()){ Log.e(TAG,"content="+response.body().string()); } } });请求结果log:
11-24 00:48:16.787 18590-18714/com.simple E/MainActivity: content={"info":[],"page":{"total":0,"pagesize":10,"page":1,"page_total":0},"state":"success"}
ok,post请求也是成功的,
文件下载
以从豆瓣网下载一个图片为例,
public void download(View view){ OkHttpClient client = new OkHttpClient(); String url = "https://img3.doubanio.com/view/photo/m/public/p2304620571.webp"; Request request = new Request.Builder().url(url).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG,"下载失败="+e); } @Override public void onResponse(Call call, Response response) { if(null!=response&&response.isSuccessful()){ Log.e(TAG,"下载成功="); InputStream inputStream = response.body().byteStream(); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(new File(getPath(),"/zgz1.jpg")); byte[] buffer = new byte[2048]; int len = 0; while ((len = inputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, len); } fileOutputStream.flush(); } catch (IOException e) { Log.e(TAG,"下载过程中失败="+e); }finally { try { if(null!=fileOutputStream){ fileOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(inputStream!=null){ inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } } }); }这是get方式文件下载.
文件上传
这个需要自己搭建服务器了,昨晚在eclipse弄了好久,就是跑不起来,今天下载了一个myeclipse,再弄弄,把刚才下载的图片上传.又弄了好久终于把这文件上传弄好了
服务端代码:
package com.simple.upload;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@MultipartConfig
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public UploadServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
String name=request.getParameter("name");
System.out.println("name="+name);
Part part=request.getPart("fileimage");
PrintWriter out=response.getWriter();
out.print("name="+name+"\n");
System.out.println("ContentType="+part.getContentType()+"\n");
out.print("ContentType="+part.getContentType()+"\n");
System.out.println("size="+part.getSize()+"\n");
out.print("size="+part.getSize()+"\n");
part.write("C://Users/zhouguizhijxhz/zgz.jpg");
}
}
客户端上传文件的代码:
public void file_upload(View view){ new Thread(){ @Override public void run() { File file = new File(getPath(),"/zgz2.jpg"); RequestBody imageBody = RequestBody.create(MediaType.parse("image/jpeg"), file); MultipartBody body = new MultipartBody.Builder(). setType(MultipartBody.FORM).//这是你再上传文件的同时还要传递参数就必须写这个setType() addFormDataPart("name", "zhouguizhi"). addFormDataPart("fileimage", "zgz.jpg", imageBody).build(); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder(). url("http://192.168.1.107:8080/aa/UploadServlet").post(body).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG,"上传文件失败原因="+e); } @Override public void onResponse(Call call, Response response) throws IOException { Log.e(TAG,"上传文件onResponse="); if (response.isSuccessful()) { Log.e(TAG,"上传文件="+response.code()); } } }); } }.start(); }
public String getPath(){ String path = Environment.getExternalStorageDirectory().getAbsolutePath(); return path; }看下myeclipse的控制台:
上传的文件我是存储在
part.write("C://Users/zhouguizhijxhz/zgz.jpg");
这个目录下:
这个文件上传,我是又下载了eclipse 不行今天又下载了myEclipse 不容易啊。
最后讲一下okhttp的缓存了,前提是你服务器端要支持缓存,如果不支持缓存的话,设置也是没毛用的.哦,还有一个设置超时的问题,这个简单,先说下,设置超时这些操作肯定是在一个全局中,就好比我们不可能每个请求都是去设置超时,所以不可能在Request类中,而是在OkhttpClient类
设置超时
看看下面这些方法,又是采用了builder模式,okhttp3框架中大量的使用了builder模式,如果不设置的话,默认是10秒.
connectTimeout = 10_000; readTimeout = 10_000; writeTimeout = 10_000; pingInterval = 0;这是它源码中的默认值,在这也简单的设置下:
OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10,TimeUnit.SECONDS) .build();
缓存设置
public void cache(View view){ new Thread(){ @Override public void run() { int maxCacheSize = 10 * 1024 * 1024; //缓存在sd卡中 Cache cache = new Cache(createMdkir(), maxCacheSize); OkHttpClient client = new OkHttpClient.Builder().cache(cache).build(); Request request = new Request.Builder().url("http://www.qq.com/"). cacheControl(new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build()). build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { Log.e(TAG,"json="+response.body().string()); } }); } }.start(); }如果成功了后会在你缓存的目录下有三个文件
接下来会整合一个简单好使用的工具类.