您的位置:首页 > 理论基础 > 计算机网络

OkHttp全面解析

2017-04-03 14:47 148 查看
据说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文件中添加[b]OKHTTP的依赖:[/b]
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、使用[b]OKHTTP进行GET请求:[/b]
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的简单使用就说到这里啦!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android http