由Square团队发明的网络框架OkHttp,想必目前火过移动互联网半边天。从由Google发明的Volley停止了更新后,而OkHttp得到了官方的认可,并在不断优化。上篇文章我们简单分析和演示了Volley的源码,不过再怎么分装,OkHttp都会以强大的功能和网络请求的优化,怒甩Volley几条街!!!
首先根据本人自己的理解和使用总结,OkHttp的优势由以下这些(实在太多了):
1.会根据连接端口的时效性和网络状态的稳定性自动恢复连接。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP;
2.OkHttp还处理了代理服务器问题和SSL握手失败问题,默认情况下,OKHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题,如果你的应用程序中集成了OKHttp,Retrofit默认会使用OKHttp处理其他网络层请求;从Android4.4开始HttpURLConnection的底层实现采用的是okHttp
3.OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和 HTTP 缓存。
4.从Android4.4开始HttpURLConnection的底层实现采用的是okHttp ,缓存响应避免重复的网络请求;
5.OkHttp使用Okio来大大简化数据的访问与存储,Okio是一个增强 java.io 和 java.nio的库,提高了数据的操作效率,相比Volley,Okio更具专向性,坚持了“逻辑与I/O分离”的原则;
6.更加灵活地支持了任务的取消策略;
7.利用Soket的传输优点,完美的扮演着传输层的角色;
…….
诸多优点,只有用了才知道!
目前,该封装库志支持:
• 一般的get请求
• 一般的post请求
• 基于Http的文件上传
• 文件下载
• 上传下载的进度回调
• 加载图片
• 支持请求回调,直接返回对象、对象集合
• 支持session的保持
• 支持自签名网站https的访问,提供方法设置下证书就行
• 支持取消某个请求
OkHttp目前主要有OkHttp2.x和OkHttp3.x两个版本,下面我们一一分析:
OkHttp2.x用法全解析
1.Android Studio 配置gradle:
compile 'com.squareup.okhttp:okhttp:2.7.5'
compile 'com.squareup.okio:okio:1.7.0'
2.异步GET请求
private void getAsynHttp() {
//创建okHttpClient对象
OkHttpClient mOkHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url("http://www.baidu.com").tag(url)
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
}
@Override
public void onResponse(final Response response) throws IOException {
String str = response.body().string();
Log.i("yzw", str);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplication(), "请求成功", Toast.LENGTH_SHORT).show();
}
});
}
});
}
运行程序log打印出来的是百度首页的html文件,基本的步骤很简单,就是创建OkHttpClient、Request和Call,最后调用Call的enqueue()方法。但是每次这么写肯定是很麻烦,肯定是要进行封装的。需要注意的是onResponse回调并不是在UI线程。
3.同步GET请求
private String getSyncHttp() throws IOException{
OkHttpClient mOkHttpClient = new OkHttpClient();
//创建请求Request
final Request request = new Request.Builder()
.url("http://www.baidu.com").tag(url)
.build();
Call call = mOkHttpClient.newCall(request);
Response mResponse=call.execute();
if (mResponse.isSuccessful()) {
return mResponse.body().string();
} else {
throw new IOException("Unexpected code " + mResponse);
}
}
同步Get请求和异步调用区别就是调用了call的execute()方法。
4.异步POST请求
private void postAsynHttp() {
OkHttpClient mOkHttpClient = new OkHttpClient();
RequestBody formBody = new FormEncodingBuilder()
.add("size", "10")
.build();
Request request = new Request.Builder()
.url("http://api.1-blog.com/biz/bizserver/article/list.do").tag(url)
.post(formBody)
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
}
@Override
public void onResponse(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();
}
});
}
});
}
post与get不同的就是要要创建RequestBody并传进Request中,同样onResponse回调不是在UI线程。
5.请求缓存设置
首先我们设置缓存路径和大小并设置给OkHttpClient:
mOkHttpClient = new OkHttpClient();
File sdcache = getExternalCacheDir();
int cacheSize = 10 * 1024 * 1024;
mOkHttpClient.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
接下来异步GET请求baidu:
private void getAsynHttp() {
//创建请求Request
final Request request = new Request.Builder()
.url("http://www.baidu.com").tag(url)
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
}
@Override
public void onResponse(final 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();
}
});
}
});
}
第一次请求会请求网络得到数据,第二次以及后面的请求则会从缓存中取出数据:
当然也有种情况是有的请求每次都需要最新的数据,则在创建Request,来设置cacheControl为“CacheControl.FORCE_NETWORK”,用来表示请求会一直请求网络得到数据:
final Request request = new Request.Builder()
.url("http://www.baidu.com")
.cacheControl(CacheControl.FORCE_NETWORK)
.build();
运行程序结果为:
6.设置超时时间
另外我们也需要设置超时的时间用来处理各种网络超时的情况,超时的原因可能是网络问题也可能是服务器响应慢等问题,OkHttp当然不会忽略这一点,它支持连接、读取和写入超时的时间设置:
mOkHttpClient = new OkHttpClient();
mOkHttpClient.setConnectTimeout(15, TimeUnit.SECONDS);
mOkHttpClient.setWriteTimeout(20, TimeUnit.SECONDS);
mOkHttpClient.setReadTimeout(20, TimeUnit.SECONDS);
7.取消请求:
/**
* 取消某单个请求任务
*/
public void cancelRequest(CharSequence url) {
try {
if (mOkHttpClient != null)
mOkHttpClient.cancel(url);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 取消全部请求任务
*/
public void cancelAllRequest() {
try {
//handler.removeCallbacksAndMessages(null);
//销毁这时候任务执行的线程池对象
mOkHttpClient().getExecutorService().shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
这里分为取消单个任务和取消全部任务。取消单个任务主要是根据创建Request对象是加的tag作为每个执行对象Call的标记;mOkHttpClient.cancel(“’)方法源码是任务调度器Dispatcher中的方法:
/** Cancel all calls with the tag {@code tag}. */
public synchronized void cancel(Object tag) {
for (AsyncCall call : readyCalls) {
if (Util.equal(tag, call.tag())) {
call.cancel();
}
}
for (AsyncCall call : runningCalls) {
if (Util.equal(tag, call.tag())) {
call.get().canceled = true;
HttpEngine engine = call.get().engine;
if (engine != null) engine.cancel();
}
}
for (Call call : executedCalls) {
if (Util.equal(tag, call.tag())) {
call.cancel();
}
}
}
而任务的全部取消这里采用的是直接关闭任务调度器中的线程池对象
8.代码的封装:
/**
* Created by ethank on 17/5/19.
*/
public class OkHttp2Engine {
private static OkHttp2Engine 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 CharSequence POST = "post";
private CharSequence GET = "get";
private Handler handler = null;