Okhttp使用和源码分析二(OkHttp3.x用法)
来源:互联网 发布:马尔可夫矩阵法例题 编辑:程序博客网 时间:2024/06/05 21:50
上一篇介绍了OkHttp2.x的用法,这一篇文章我们来对照OkHttp2.x版本来看看,OkHttp3使用起来有那些变化?
1.使用前准备,Android Studio 配置gradle:
compile 'com.squareup.okhttp3:okhttp:3.2.0'compile 'com.squareup.okio:okio:1.7.0'
添加网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
2.异步GET请求
private void getAsynHttp() { mOkHttpClient=new OkHttpClient(); Request.Builder requestBuilder = new Request.Builder().url("http://www.baidu.com"); //可以省略,默认是GET请求 requestBuilder.method("GET",null); Request request = requestBuilder.build(); Call mcall= mOkHttpClient.newCall(request); mcall.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { if (null != response.cacheResponse()) { String str = response.cacheResponse().toString(); Log.i("yzw", "cache---" + str); } else { response.body().string(); String str = response.networkResponse().toString(); Log.i("yzw", "network---" + str); } runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show(); } }); } });}
与2.x版本并没有什么不同,比较郁闷的是回调仍然不在UI线程。
2.异步POST请求
OkHttp3异步POST请求和OkHttp2.x有一些差别就是没有FormEncodingBuilder这个类,替代它的是功能更加强大的FormBody:
private void postAsynHttp() { mOkHttpClient=new OkHttpClient(); RequestBody formBody = new FormBody.Builder() .add("size", "10") .build(); Request request = new Request.Builder() .url("http://api.1-blog.com/biz/bizserver/article/list.do") .post(formBody) .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 { String str = response.body().string(); Log.i("yzw", str); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show(); } }); } }); }
3.异步上传文件
上传文件本身也是一个POST请求,上一篇没有讲,这里我们补上。首先定义上传文件类型:
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
将sdcard根目录的wangshu.txt文件上传到服务器上:
private void postAsynFile() { mOkHttpClient=new OkHttpClient(); File file = new File("/sdcard/wangshu.txt"); Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)) .build(); mOkHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { Log.i("yzw",response.body().string()); } }); }
当然如果想要改为同步的上传文件只要调用 mOkHttpClient.newCall(request).execute()就可以了。
当然不要忘了添加如下权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
4.异步下载文件
下载文件同样在上一篇没有讲到,实现起来比较简单,在这里下载一张图片,我们得到Response后将流写进我们指定的图片文件中就可以了。
private void downAsynFile() { mOkHttpClient = new OkHttpClient(); String url = "http://img.my.csdn.net/uploads/201603/26/1458988468_5804.jpg"; Request request = new Request.Builder().url(url).build(); mOkHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) { InputStream inputStream = response.body().byteStream(); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(new File("/sdcard/wangshu.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.i("wangshu", "IOException"); e.printStackTrace(); } Log.d("wangshu", "文件下载成功"); } });}
5.异步上传Multipart文件
这种场景很常用,我们有时会上传文件同时还需要传其他类型的字段,OkHttp3实现起来很简单,需要注意的是没有服务器接收我这个Multipart文件,所以这里只是举个例子,具体的应用还要结合实际工作中对应的服务器。
首先定义上传文件类型:
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");private void sendMultipart(){ mOkHttpClient = new OkHttpClient(); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("title", "yzw") .addFormDataPart("image", "yzw.png", RequestBody.create(MEDIA_TYPE_PNG, new File("/sdcard/yzw.jpg"))) .build(); Request request = new Request.Builder() .header("Authorization", "Client-ID " + "...") .url("https://api.imgur.com/3/image") .post(requestBody) .build(); mOkHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { Log.i("yzw", response.body().string()); } });}
6.设置超时时间和缓存
和OkHttp2.x有区别的是不能通过OkHttpClient直接设置超时时间和缓存了,而是通过OkHttpClient.Builder来设置,通过builder配置好OkHttpClient后用builder.build()来返回OkHttpClient,所以我们通常不会调用new OkHttpClient()来得到OkHttpClient,而是通过builder.build():
File sdcache = getExternalCacheDir();int cacheSize = 10 * 1024 * 1024;OkHttpClient.Builder builder = new OkHttpClient.Builder() .connectTimeout(15, TimeUnit.SECONDS) .writeTimeout(20, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .cache(new Cache(sdcache.getAbsoluteFile(), cacheSize));OkHttpClient mOkHttpClient=builder.build();
7.关于取消请求和封装
取消请求仍旧可以调用call.cancel(),只是这一版中增加了一个cancelAll()的方法:
/** * 取消某单个请求任务 */ public void cancelRequest(CharSequence url) { try { //任务调度中正在排队的任务 for (Call call : okHttpClient.dispatcher().queuedCalls()) { if (call.request().tag().equals(url)) call.cancel(); } //任务调度中正在执行的任务 for (Call call : okHttpClient.dispatcher().runningCalls()) { if (call.request().tag().equals(url)) call.cancel(); } } catch (Exception e) { e.printStackTrace(); } } /** * 取消全部请求任务 */ public void cancelAllRequest() { try { okHttpClient.dispatcher().cancelAll(); } catch (Exception e) { e.printStackTrace(); } }
8.封装
public class OkHttp3Engine { private static OkHttp3Engine mInstance; private OkHttpClient okHttpClient = null; private int DEFAULT_HTTP_TIMEOUT = 15_000; private int SIZE_OF_CACHE = 5 * 1024 * 1024; private CharSequence StringEncode = "utf-8"; private static final MediaType Json = MediaType.parse("application/json; charset=utf-8"); private static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8"); private CharSequence POST = "post"; private CharSequence GET = "get"; private Handler handler = null; private boolean hasCache = true; public OkHttp3Engine() { super(); handler = new Handler(Looper.getMainLooper()); OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.connectTimeout(DEFAULT_HTTP_TIMEOUT, TimeUnit.SECONDS); builder.readTimeout(DEFAULT_HTTP_TIMEOUT, TimeUnit.SECONDS); builder.writeTimeout(DEFAULT_HTTP_TIMEOUT, TimeUnit.SECONDS); okHttpClient = builder.build(); } public static OkHttp3Engine getInstance() { if (mInstance == null) { synchronized (OkHttp3Engine.class) { if (mInstance == null) { mInstance = new OkHttp3Engine(); } } } return mInstance; } public <T> void fetchStringPost(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, FetchDataInterface fetchDatainterface) { fetchString(url.toString(), resultBean, map, POST, false, null, fetchDatainterface); } public <T> void fetchStringGet(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, FetchDataInterface fetchDatainterface) { fetchString(url.toString(), resultBean, map, GET, false, null, fetchDatainterface); } public <T> void fetchStringAsyncPost(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, FetchDataInterface fetchDatainterface) { AsyncfetchString(url.toString(), resultBean, map, POST, false, null, fetchDatainterface); } public <T> void fetchStringAsyncGet(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, FetchDataInterface fetchDatainterface) { AsyncfetchString(url.toString(), resultBean, map, GET, false, null, fetchDatainterface); } public <T> void fetchStringPostJson(CharSequence url, T resultBean, CharSequence json, FetchDataInterface fetchDatainterface) { fetchString(url.toString(), resultBean, null, POST, true, json, fetchDatainterface); } public <T> void fetchStringAsyncPostJson(CharSequence url, T resultBean, CharSequence json, FetchDataInterface fetchDatainterface) { AsyncfetchString(url.toString(), resultBean, null, POST, true, json, fetchDatainterface); } public void setOkHttpCache(boolean hasCache, Context mContext) { this.hasCache = hasCache; File cacheDirectory = new File(mContext.getExternalCacheDir(), "HttpCache"); OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.connectTimeout(DEFAULT_HTTP_TIMEOUT, TimeUnit.SECONDS); builder.readTimeout(DEFAULT_HTTP_TIMEOUT, TimeUnit.SECONDS); builder.writeTimeout(DEFAULT_HTTP_TIMEOUT, TimeUnit.SECONDS); if (okHttpClient != null) { okHttpClient.dispatcher().cancelAll(); } if (hasCache) { Cache cache = new Cache(cacheDirectory, SIZE_OF_CACHE); okHttpClient = builder.cache(cache).build(); } else { okHttpClient = builder.build(); } } public boolean isHasCache() { return hasCache; } /** * 取消某单个请求任务 */ public void cancelRequest(CharSequence url) { try { //任务调度中正在排队的任务 for (Call call : okHttpClient.dispatcher().queuedCalls()) { if (call.request().tag().equals(url)) call.cancel(); } //任务调度中正在执行的任务 for (Call call : okHttpClient.dispatcher().runningCalls()) { if (call.request().tag().equals(url)) call.cancel(); } } catch (Exception e) { e.printStackTrace(); } } /** * 取消全部请求任务 */ public void cancelAllRequest() { try { okHttpClient.dispatcher().cancelAll(); } catch (Exception e) { e.printStackTrace(); } } /** * 回调接口 */ public interface FetchDataInterface { <T> void successful(T result); void failed(CharSequence message); } /** * 同步请求 */ private <T> void fetchString(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, CharSequence method, boolean isSendJson, CharSequence json, FetchDataInterface fetchDatainterface) { Request request = null; try { if (method.equals(POST)) { RequestBody body = null; if (isSendJson) { body = RequestBody.create(Json, json.toString()); } else { //pMap.put("param", JSONObject.toJSONString(map)); body = mapToRequestBody(map); } if (isHasCache()) request = new Request.Builder().tag(url).url(new URI(url.toString()).toURL()).post(body).build(); else { request = new Request.Builder().tag(url).url(new URI(url.toString()).toURL()).cacheControl(CacheControl.FORCE_CACHE).post(body).build(); } } else { //CharSequence param = setMapToParam(map).toString(); if (isHasCache()) request = new Request.Builder().tag(url).url(new URI(builderGetUri(url.toString(), map).toString()).toURL()).get().build(); else { request = new Request.Builder().tag(url).url(new URI(builderGetUri(url.toString(), map).toString()).toURL()).cacheControl(CacheControl.FORCE_CACHE).get().build(); } } Response response = okHttpClient.newCall(request).execute(); if (null == response || !response.isSuccessful()) { sendCallBack("respponse isnull", false, fetchDatainterface); return; } byte[] bytes = response.body().bytes(); if (null == bytes) { sendCallBack("responsebody isnull", false, fetchDatainterface); return; } String result = new String(bytes, StringEncode.toString()); if (TextUtils.isEmpty(result)) { sendCallBack("strcode isnull", false, fetchDatainterface); return; } /** * 判断返回的是否是json格式的数据 */ JSONObject jsonString = JSON.parseObject(result); T t = (T) JSON.parseObject(jsonString.toString(), resultBean.getClass()); sendCallBack(t, true, fetchDatainterface); } catch (Exception e) { e.printStackTrace(); sendCallBack(e.getMessage(), false, fetchDatainterface); } } /** * 异步请求 */ private <T> void AsyncfetchString(final CharSequence url, final T resultBean, Map<CharSequence, CharSequence> map, CharSequence method, boolean isSendJson, final CharSequence json, final FetchDataInterface fetchDatainterface) { Request request = null; try { if (method.equals(POST)) { RequestBody body = null; if (isSendJson) { body = RequestBody.create(Json, json.toString()); } else { //pMap.put("param", JSONObject.toJSONString(map)); body = mapToRequestBody(map); } if (isHasCache()) request = new Request.Builder().tag(url).url(new URI(url.toString()).toURL()).post(body).build(); else request = new Request.Builder().tag(url).url(new URI(url.toString()).toURL()).cacheControl(CacheControl.FORCE_CACHE).post(body).build(); } else { //CharSequence param = setMapToParam(map).toString(); if (isHasCache()) request = new Request.Builder().tag(url).url(new URI(builderGetUri(url.toString(), map).toString()).toURL()).get().build(); else request = new Request.Builder().tag(url).url(new URI(builderGetUri(url.toString(), map).toString()).toURL()).cacheControl(CacheControl.FORCE_CACHE).get().build(); } okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) throws IOException { if (null == response || !response.isSuccessful()) { sendCallBack("response isnull", false, fetchDatainterface); return; } byte[] bytes = response.body().bytes(); if (null == bytes) { sendCallBack("responsebody isnull", false, fetchDatainterface); return; } String result = new String(bytes, StringEncode.toString()); if (TextUtils.isEmpty(result)) { sendCallBack("strcode isnull", false, fetchDatainterface); return; } /** * 判断返回的是否是json格式的数据 */ try { JSONObject jsonString = JSON.parseObject(result); T t = (T) JSON.parseObject(jsonString.toString(), resultBean.getClass()); sendCallBack(t, true, fetchDatainterface); } catch (Exception e) { e.printStackTrace(); sendCallBack(e.getMessage(), false, fetchDatainterface); } } @Override public void onFailure(Call call, IOException e) { sendCallBack(e.getMessage(), false, fetchDatainterface); } }); } catch (Exception e) { e.printStackTrace(); sendCallBack(e.getMessage(), false, fetchDatainterface); } } private RequestBody mapToRequestBody(Map<CharSequence, CharSequence> kv) throws IOException { FormBody.Builder formBody = new FormBody.Builder(); for (CharSequence key : kv.keySet()) { formBody.add(key.toString(), kv.get(key).toString()); } return formBody.build(); } private CharSequence setMapToParam(Map<CharSequence, CharSequence> hashMap) { StringBuilder param = new StringBuilder(); if (hashMap == null || hashMap.size() == 0) { return ""; } for (Map.Entry<CharSequence, CharSequence> entry : hashMap.entrySet()) { // 如果请求参数中有中文,需要进行URLEncoder编码 if (entry.getValue() != null) { try { param.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue().toString(), StringEncode.toString())); param.append("&"); } catch (Exception e) { e.printStackTrace(); } } } if (param.length() > 0) { param.deleteCharAt(param.length() - 1); } return param.toString(); } private CharSequence builderGetUri(CharSequence uri, Map<CharSequence, CharSequence> map) { StringBuilder sb = new StringBuilder(); try { while (uri.toString().endsWith("/")) { try { uri = uri.toString().substring(0, uri.length() - 1); } catch (Exception e) { e.printStackTrace(); } } sb.append(uri).append("?"); if (map != null && map.size() != 0) { for (Map.Entry<CharSequence, CharSequence> entry : map.entrySet()) { // 如果请求参数中有中文,需要进行URLEncoder编码 sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue().toString(), StringEncode.toString())); sb.append("&"); } sb.deleteCharAt(sb.length() - 1); } } catch (Exception e) { e.printStackTrace(); } Log.d("builderGetUri", sb.toString()); return sb.toString(); } /** * 文件上传 * * @param url 上传的服务器地址 * @param file 上传的本地文件 * @param params 上传文件时带的参数 * @param fetchDatainterface 上传完成后的回调接口 */ public void uploadFile(final CharSequence url, File file, Map<String, String> params, final FetchDataInterface fetchDatainterface) { Request request = new Request.Builder().headers(Headers.of(params)).url(url.toString()).post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)).build(); Call call = okHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { sendCallBack(e.getMessage(), false, fetchDatainterface); } @Override public void onResponse(Call call, Response response) throws IOException { sendCallBack(response.body().string(), true, fetchDatainterface); } }); } /** * 文件下载 * * @param url 下载的服务器地址 * @param localSavePath 下载后保存的本地地址 * @param fetchDatainterface 下载完成后的回调接口 */ public void downloadFile(final String url, final String localSavePath, final FetchDataInterface fetchDatainterface) throws Exception { Request request = new Request.Builder().url(url).build(); okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { sendCallBack(e.getMessage(), false, fetchDatainterface); } @Override public void onResponse(Call call, Response response) { try { InputStream inputStream = response.body().byteStream(); FileOutputStream fileOutputStream = new FileOutputStream(new File(localSavePath)); byte[] buffer = new byte[2048]; int len = 0; while ((len = inputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, len); } inputStream.close(); fileOutputStream.flush(); fileOutputStream.close(); sendCallBack(localSavePath, true, fetchDatainterface); } catch (IOException e) { Log.i("downloadFile", "IOException"); e.printStackTrace(); } Log.d("downloadFile", "文件下载成功"); } }); } /** * 图片下载并展示 * * @param image 展示的控件 * @param url 下载的地址 */ public void downloadImgShowImageView(final ImageView image, final String url) throws Exception { Request request = new Request.Builder().url(url).build(); Call call = okHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { image.setImageResource(0); } @Override public void onResponse(Call call, Response response) throws IOException { InputStream is = response.body().byteStream(); ImageUtils.ImageSize actualImageSize = ImageUtils.getImageSize(is); ImageUtils.ImageSize imageViewSize = ImageUtils.getImageViewSize(image); int inSampleSize = ImageUtils.calculateInSampleSize(actualImageSize, imageViewSize); try { is.reset(); } catch (Exception e) { Request request = new Request.Builder().url(url).build(); response = okHttpClient.newCall(request).execute(); is = response.body().byteStream(); } BitmapFactory.Options ops = new BitmapFactory.Options(); ops.inJustDecodeBounds = false; ops.inSampleSize = inSampleSize; final Bitmap bm = BitmapFactory.decodeStream(is, null, ops); image.post(new Runnable() { @Override public void run() { image.setImageBitmap(bm); } }); is.close(); } }); } private <T> void sendCallBack(final T t, final boolean isSccessful, final FetchDataInterface fetchDatainterface) { handler.post(new Runnable() { @Override public void run() { if (isSccessful) fetchDatainterface.successful(t); else fetchDatainterface.failed(t.toString()); } }); }}
我们以一个get请求为例使用:
OkHttp3Engine.getInstance().fetchStringAsyncGet("http://www.baidu.com", new String(), null, new OkHttp3Engine.FetchDataInterface() { @Override public <T> void successful(T result) { Log.d("yzw", result.toString()); } @Override public void failed(CharSequence message) { } });
博文参考:http://liuwangshu.cn/application/network/6-okhttp3.html
- Okhttp使用和源码分析二(OkHttp3.x用法)
- Okhttp使用和源码分析一(OkHttp2.x用法)
- Okhttp使用和源码分析三(OkHttp源码分析)
- OkHttp3源码分析(二)
- Okhttp 框架使用和源码分析
- Okhttp源码分析-流程分析(1)-基于最新okhttp3.4.1
- OkHttp3源码分析
- OkHttp3源码分析[综述]
- okHttp3源码简要分析
- okhttp3 源码深入分析
- OkHttp3源码分析[综述]
- OkHttp3源码分析[DiskLruCache]
- okhttp3 源码分析
- 关于OkHttp3源码分析
- OKHttp源码分析(二)之RequestBody
- okhttp源码分析(二)-RetryAndFollowUpInterceptor过滤器
- Android 源码分析之okhttp3(builder二)
- OkHttp3.4.x源码剖析
- 动态加载布局LayoutInflater.inflate()源代码解析
- 【Spring学习笔记】Spring Aop细说
- C++网站开发MVC框架TreeFrog Framework教程——4.生成器
- python ---- set
- JavaWeb(八)Cookie入门
- Okhttp使用和源码分析二(OkHttp3.x用法)
- Oracle 子查询
- c
- Android主题切换(一),基本使用流程
- FMDB解析和简单使用
- 【LeetCode】120. Triangle
- OPENCV3的匹配
- java虚拟机之垃圾收集器与内存分配策略
- AndroidStudio获得屏幕分辨率