Android网络框架学习之OkHttp
来源:互联网 发布:淘宝大学vip课程 编辑:程序博客网 时间:2024/05/29 07:24
OkHttp官网地址
OkHttp GitHub地址
官网中有很详细的Java doc文档,我们可以很方便的查到OkHttp里面各个API的功能和使用方法。
get方式获取数据
private String doGet(String areaId) { //1.创建一个okClient对象 OkHttpClient client = new OkHttpClient(); //2.创建一个Request请求 String url = String.format(URL_Weather,areaId); Request request = new Request.Builder().url(url).build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d(TAG,"请求服务器失败"); } @Override public void onResponse(Call call, Response response) throws IOException { // 注:该回调是子线程,非主线程 Log.d(TAG,"请求服务器成功:"); weatherResult = response.body().string(); } }); return weatherResult; }
以上是OkHttp的异步get请求,是okhttp3异步方法,不需要我们开启工作线程执行网络请求,返回的结果也在工作线程中;
Response response = client.newCall(request).execute(); if (response.isSuccessful()) { return response.body().string(); } else { throw new IOException("Unexpected code " + response); }
以上是同步方法,如果使用同步get方法,需要自行开辟子线程进行网络请求,此处不推荐~
post方式获取数据
OkHttp的post方法可以提交键值对、文本、Stream、file等形式的数据,然后使用Request的post方法来提交请求体RequestBody。
private String doPost(String areaId) { new Thread(new Runnable() { @Override public void run() { try { // 请求完整url:http://api.k780.com:88/?app=weather.future&weaid=101281001&&appkey=%s&sign=%s&format=json String url = "http://api.k780.com:88/"; OkHttpClient.Builder builder = new OkHttpClient.Builder() .connectTimeout(800, TimeUnit.MILLISECONDS) .cache(new Cache(getExternalCacheDir().getAbsoluteFile(),10*1024*1024)) .writeTimeout(5, TimeUnit.SECONDS); OkHttpClient okHttpClient = builder.build(); RequestBody formBody = new FormBody.Builder().add("app", "weather.future") .add("weaid", "101281001").add("appkey", APPKEY).add("sign", SIGN).add("format", "json") .build(); Request request = new Request.Builder().url(url).post(formBody).build(); okhttp3.Response response = okHttpClient.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); weatherResult = response.body().string(); Log.i(TAG, weatherResult); } catch (Exception e) { e.printStackTrace(); } } }).start(); return weatherResult; }
以下代码参考自OkHttp官方示例:Http官方教程
post提交流:
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");private final OkHttpClient client = new OkHttpClient();public void run() throws Exception { RequestBody requestBody = new RequestBody() { @Override public MediaType contentType() { return MEDIA_TYPE_MARKDOWN; } @Override public void writeTo(BufferedSink sink) throws IOException { sink.writeUtf8("Numbers\n"); sink.writeUtf8("-------\n"); for (int i = 2; i <= 997; i++) { sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i))); } } private String factor(int n) { for (int i = 2; i < n; i++) { int x = n / i; if (x * i == n) return factor(x) + " × " + i; } return Integer.toString(n); } }; Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(requestBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string());}
post提交文件:
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");private final OkHttpClient client = new OkHttpClient();public void run() throws Exception { File file = new File("README.md"); Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string());
post提交表单(键值对):
private final OkHttpClient client = new OkHttpClient();public void run() throws Exception { RequestBody formBody = new FormBody.Builder() .add("search", "Jurassic Park") .build(); Request request = new Request.Builder() .url("https://en.wikipedia.org/w/index.php") .post(formBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string());}
此处需注意:
okHttp2.7用的是new FormEncodingBuilder(),而OkHttp3.x用的是FormBody.Builder();
Post提交String
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");private final OkHttpClient client = new OkHttpClient();public void run() throws Exception { String postBody = "" + "Releases\n" + "--------\n" + "\n" + " * _1.0_ May 6, 2013\n" + " * _1.1_ June 15, 2013\n" + " * _1.2_ August 11, 2013\n"; Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody)) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string());}
Post提交分块请求
MultipartBuilder可以构建复杂的请求体,与HTML文件上传形式兼容。多块请求体中每块请求都是一个请求体,可以定义自己的请求头。这些请求头可以用来描述这块请求,例如他的Content-Disposition。如果Content-Length和Content-Type可用的话,他们会被自动添加到请求头中。
private static final String IMGUR_CLIENT_ID = "...";private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");private final OkHttpClient client = new OkHttpClient();public void run() throws Exception { // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM) .addPart( Headers.of("Content-Disposition", "form-data; name=\"title\""), RequestBody.create(null, "Square Logo")) .addPart( Headers.of("Content-Disposition", "form-data; name=\"image\""), RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png"))) .build(); Request request = new Request.Builder() .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID) .url("https://api.imgur.com/3/image") .post(requestBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); System.out.println(response.body().string());}
此处OkHttp3也有和之前版本不一样的地方,OkHttp3使用了MultipartBody.Builder()的方法来创建RequestBody,而之前是使用MultipartBuilder()。
更多OkHttp的改动详见:okhttp3与旧版本okhttp的区别分析
关于MediaType
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式
以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml : XML数据格式
application/atom+xml :Atom XML聚合格式
application/json : JSON数据格式
application/pdf :pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded : 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
另外一种常见的媒体格式是上传文件之时使用的:
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
注意:MediaType.parse(“image/png”)里的”image/png”不知道该填什么,可以参考—》http://www.w3school.com.cn/media/media_mimeref.asp
如何使用呢?(在请求体里面写入类型和需要写入的数据,通过post请求)
String body = “hdsoifhjoihdsfh”;
RequestBody body = RequestBody.create(MEDIA_TYPE_MARKDOWN, body);
设置缓存目录和大小:
响应缓存使用HTTP头作为配置。你可以在请求头中添加Cache-Control: max-stale=3600 ,OkHttp缓存会支持。你的服务通过响应头确定响应缓存多长时间,例如使用Cache-Control: max-age=9600。
public CacheResponse(File cacheDirectory) throws Exception { int cacheSize = 10 * 1024 * 1024; // 10 MiB Cache cache = new Cache(cacheDirectory, cacheSize); client = new OkHttpClient(); client.setCache(cache);}
设置超时时间和缓存
和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();
代码示例:
private String doGet(String areaId) { String url = String.format(URL_Weather, areaId); 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) { Log.d(TAG, "请求服务器失败"); } @Override public void onResponse(Call call, Response response) throws IOException { Log.d(TAG, "请求服务器成功:\n"+response.body().string()); } }); return weatherResult; } private String doPost(String areaId) { try { // 请求完整url:http://api.k780.com:88/?app=weather.future&weaid=101281001&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json String url = "http://api.k780.com:88/"; RequestBody formBody = new FormBody.Builder().add("app", "weather.future") .add("weaid", areaId).add("appkey", "10003").add("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4").add("format", "json") .build(); Request request = new Request.Builder().url(url).post(formBody).build(); Call call = okHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { weatherResult = response.body().string(); Log.i(TAG, weatherResult); } }); } catch (Exception e) { e.printStackTrace(); } return weatherResult; } private void doUpload() { File file = new File("/sdcard/zoky.txt"); Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)) .build(); okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d(TAG,"上传失败"); } @Override public void onResponse(Call call, Response response) throws IOException { Log.i(TAG, "上传成功:\n" + response.body().string()); } }); } private void doDownload() { String url = "http://avatar.csdn.net/5/8/5/1_zoky_ze.jpg"; Request request = new Request.Builder().url(url).build(); okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d(TAG,"下载失败"); } @Override public void onResponse(Call call, Response response) { int len; InputStream inputStream = response.body().byteStream(); FileOutputStream fileOutputStream; try { fileOutputStream = new FileOutputStream(new File("/sdcard/zoky.jpg")); byte[] buffer = new byte[2048]; while ((len = inputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, len); } fileOutputStream.flush(); Log.d(TAG, "文件下载成功"+ response.body().string()); } catch (IOException e) { e.printStackTrace(); } } }); }
github示例
内部调用流程
有上图可以看出,OkHttp不管是异步调用还是同步调用,最终都是通过getResponseWithInterceptorChain()方法来进行网络请求
Response getResponseWithInterceptorChain() throws IOException {// Build a full stack of interceptors.List<Interceptor> interceptors = new ArrayList<>();interceptors.addAll(client.interceptors());interceptors.add(retryAndFollowUpInterceptor);interceptors.add(new BridgeInterceptor(client.cookieJar()));interceptors.add(new CacheInterceptor(client.internalCache()));interceptors.add(new ConnectInterceptor(client));if (!forWebSocket) { interceptors.addAll(client.networkInterceptors());}interceptors.add(new CallServerInterceptor(forWebSocket));Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest);return chain.proceed(originalRequest);}
在getResponseWithInterceptorChain()方法中加了一些拦截器,然后启动一个拦截器调用链,拦截器递归调用之后最后返回请求的响应Response。这里的拦截器分层的思想就是借鉴的网络里的分层模型的思想。请求从最上面一层到最下一层,响应从最下一层到最上一层,每一层只负责自己的任务,对请求或响应做各自的操作。OkHttp还支持用户自定义拦截器,插入到最顶层和CallServerInterceptor上一层的位置。square官方就有一个Logging Interceptor,用于打印网络请求日志的拦截器。
下图是拦截器的调用流程及各自的执行的操作。
RealInterceptorChain的proceed(),每次重新创建一个RealInterceptorChain对象,然后调用下一层的拦截器的interceptor.intercept()方法。
@Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // 1、该拦截器在Request阶段负责的事情 // 2、调用RealInterceptorChain.proceed(),其实是递归调用下一层拦截器的intercept方法 response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null); //3、该拦截器在Response阶段负责的事情,然后返回到上一层拦截器的 response阶段 return response; } }
参考文章:
OkHttp使用进阶 译自OkHttp Github官方教程
OkHttp3用法全解析
okhttp3与旧版本okhttp的区别分析
Android OkHttp完全解析 是时候来了解OkHttp了
OkHTT分析
- okhttp,Android网络框架学习之OKHttp
- Android 网络框架学习之OKHttp
- Android网络框架学习之OkHttp
- Android 开发框架之okhttp 网络框架的学习
- Android 网络框架OKHttp学习
- android 网络框架学习(okhttp,retrofit,rxjava)
- Android 网络框架之 OkHttp 基础使用
- Android OkHttp 框架学习
- android 网络框架解析--OKHttp
- Android网络框架-OkHttp使用
- Android网络框架-OkHttp使用
- Android网络框架OKHttp初解
- Android学习笔记02——OKHttp网络框架01
- Android 的OkHttp 网络请求框架的学习封装
- android网络框架OkHttp之get请求(源码初识)
- android网络框架OkHttp之get请求(源码初识)
- Android网络框架之Retrofit + RxJava + OkHttp
- Android-第三方框架-网络请求之okhttp
- Java6.0新特性之StAX--全面解析Java XML分析技术
- CCS6.0与MATLAB 2013a的链接配置
- 20170301ZABBIX proxy 3.2.1安装
- block的使用规范:
- maven build卡死在Downloading metadata的解决方案
- Android网络框架学习之OkHttp
- 从最佳并发用户数和最大并发用户数看性能测试
- bindService不调用onServiceConnected的问题
- 最简单的理解tensorflow分布式计算的例子
- maven setting.xml配置说明
- sublime text3 常用插件汇总
- Python 字符串常量
- 开源商城WSTMart支付开发研究[转]
- linux配置bond网卡绑定与修改IP地址