据说Android4.4的源码中可以看到HttpURLConnection已经替换成OkHttp实现了。所以我们更有理由相信OkHttp的强大。
OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。
使用 OkHttp 无需重写您程序中的网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的API。如果你用了 Apache HttpClient,则OkHttp也提供了一个对应的okhttp-apache 模块。
首先在Module的gradle文件中添加OKHTTP的依赖:
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.3.1' testCompile 'junit:junit:4.12' compile 'com.squareup.okhttp3:okhttp:3.6.0' }
1、使用OKHTTP进行GET请求:
OkHttpClient okHttpClient = new OkHttpClient(); Request.Builder builder = new Request.Builder().url(JuHeURL.getURL("红烧肉")); //可以省略,默认是get请求 builder.method("GET", null); final Request request = builder.build(); Call mCall = okHttpClient.newCall(request);
在主线程中执行同步的请求,需要自己手动开启线程,可以忽略,后面的例子不会再有同步的,都一样!
try { //同步访问网络,需要自己手动开启一个线程 Response response=mCall.execute(); } catch (IOException e) { e.printStackTrace(); }
这里主要讲一下异步请求:
//异步请求 mCall.enqueue(new Callback() { @Override//请求错误 public void onFailure(Call call, IOException e) { Log.i(TAG, "onFailure:" + e.toString()); } @Override//请求成功 public void onResponse(Call call, Response response) throws IOException { String str = null; if (null != response.cacheResponse()) { str = response.cacheResponse().toString(); Log.i(TAG, "onResponse:-----------str" + str); } else { str = response.networkResponse().toString(); Log.i(TAG, "onResponse:===========str:" + str); } }
Request是OkHttp中访问的请求类,Builder是辅助类。Response是OkHttp中的响应类。请求成功后的Response对象的
response.body()返回ResponseBody类的对象,该对象可以很方便的获得返回的字符串或者是流的形式(后面的异步下载文件有示范!)。
这里需要注意一下,请求成功后回调的onResponse方法中的response对象的:第一次使用response.body().string()方法
的时候
可以正确拿到数据,第二次就会报错:java.lang.IllegalStateException: 为什么会这个样子呢?这里解释一下:因为response.body()也是挺大的,OkHttp没有把它存储在内存中,你需要的时候就去读一次,只给你了内容,没有给引用,所以一次请求只能读一次!
回到源码,我们去看看:
public final String string() throws IOException { BufferedSource source = source(); try { Charset charset = Util.bomAwareCharset(source, charset()); return source.readString(charset); } finally { Util.closeQuietly(source); } }
看!!!!我们都知道finally中的代码肯定会调用这里执行
Util.closeQuietly(source);~~~~
closeQuietly方法可以运用到各类可关闭的对象中
所以懂了
就是因为在拿过之后就把资源关闭了
所以就获取不到了,所以只能拿一次。
也算是个小坑,记录记录~~~~
当然,OKHTTP也支持我们取消一个Call:
//立即停止掉一个正在执行的call mCall.cancel();如果一个线程正在写请求或者读响应,将会引发
IOException
。当call没有必要的时候,使用这个api可以节约网络资源。例如当用户离开一个应用时。不管同步还是异步的call都可以取消!
你也可以通过tags来同时取消多个请求。当你构建一请求时,使用RequestBuilder.tag(tag)
来分配一个标签。之后你就可以用OkHttpClient.cancel(tag)
来取消所有带有这个tag的call。
2、使用OKHTTP进行POST请求:
String url = "http://api.1-blog.com/biz/bizserver/article/list.do"; OkHttpClient okHttpClient = new OkHttpClient(); //很多时候我们会需要通过POST方式把键值对数据传送到服务器 RequestBody RequestBody = new FormBody.Builder() .add("size", "10") .add("platform","android") .add("name","bug") .build(); Request request = new Request.Builder().url(url).post(RequestBody).build(); Call call = okHttpClient.newCall(request);当然,我这边的URL你测试的时候还是要换一下的哦!post请求的辅助类RequestBoby,以及他的add方法,把参数传进去!
//异步请求 call.enqueue(new Callback() { @Override//请求错误 public void onFailure(Call call, IOException e) { Log.i(TAG, "onFailure: " + e.toString()); } @Override//请求成功 public void onResponse(Call call, Response response) throws IOException { String str = response.body().string(); Log.i(TAG, "onResponse: " + str); } });
3、异步上传文件:
//上传文件本身也是一个POST请求,首先定义上传文件类型: MediaType maMediaType = MediaType.parse("text/x-markdown; charset=utf-8"); OkHttpClient okHttpClient = new OkHttpClient(); File file = new File("/sdcard/wangshu.txt"); Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(maMediaType, file)) .build();
//将文件上传到服务器上: okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.i(TAG, "onFailure: " + e.toString()); } @Override public void onResponse(Call call, Response response) throws IOException { Log.i(TAG, "onResponse: " + response.body().string()); } });
4、异步上传Multipart文件:
这种情况还比较常见,当我们需要上传文件的同时还要上传其他类型的字段,实现起来很简单,这里只是举个例子,具体的应用要结合实际工作中对应的服务器:
//首先定义上传文件类型: MediaType mediaType = MediaType.parse("image/png"); OkHttpClient okHttpClient = new OkHttpClient(); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("title", "wangshu") .addFormDataPart("image", "wangshu.jpg", RequestBody.create(mediaType, new File("/sdcard/wangshu.jpg"))) .build(); Request request = new Request.Builder() .header("Authorization", "Client-ID " + "...") .url("https://api.imgur.com/3/image") .post(requestBody) .build();
okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.i(TAG, "onFailure: " + e.toString()); } @Override public void onResponse(Call call, Response response) throws IOException { Log.i(TAG, "onResponse: " + response.body().string()); } });
5、异步下载文件:
OkHttpClient okHttpClient = new OkHttpClient(); String url = "http://imgsrc.baidu.com/baike/pic/item/b58f8c5494eef01f579b09d2e4fe9925bc317d1d.jpg"; Request request = new Request.Builder().url(url).build();
okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.i(TAG, "onFailure: " + e.toString()); } @Override public void onResponse(Call call, Response response) throws IOException { InputStream inputStream = response.body().byteStream(); FileOutputStream outputStream = null; try { outputStream = new FileOutputStream(new File("/sdcard/我的杨钰莹.jpg")); byte[] buBytes = new byte[2048]; int let = 0; while ((let = inputStream.read(buBytes)) != -1) { outputStream.write(buBytes, 0, let); } outputStream.flush(); } catch (IOException e) { Log.i(TAG, "onResponse: 文件下载出错了...."); e.printStackTrace(); } Log.i(TAG, "onResponse: 文件下载成功!----------------------------"); } });
6、设置OKHTTP的超时时间和缓存:
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 okHttpClient=builder.build(); }
这里需要说明的就是:getExternalCacheDir()方法可以获取到 SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据
如果使用该方法,当你的应用在被用户卸载后,SDCard/Android/data/你的应用的包名/ 这个目录下的所有文件都会被删除,不会留下垃圾信息。目录对应 设置->应用->应用详情里面的”清除缓存“选项。
好了,这次的OKHTTP的简单使用就说到这里啦!