OkHttp的Github地址:https://github.com/square/okhttp
OkHttp非常高效,支持SPDY、连接池、GZIP和HTTP缓存。
在Android Studio中使用不需要下载jar包,直接添加依赖即可:
compile 'com.squareup.okhttp3:okhttp:3.13.1'
添加上述依赖会自动下载两个库,一个是OkHttp库,一个是Okio库,后者是前者的通讯基础。
添加权限
<uses-permission android:name="android.permission.INTERNET"/>
同步请求:执行请求的操作是阻塞式,直到HTTP响应返回。
(OKHttp的execute方法是同步方法)
异步请求:类似于非阻塞式请求,它的执行结果一般都是通过接口回调的方式告知调用者。
(OkHttp的enqueue方法是异步方法)
常用的方法主要有两个:GET和POST。GET表示希望从服务器那里获取数据,而POST则表示希望提交数据给服务器。
注:Android4.4之后的HttpUrlConnection的实现是基于OkHttp。
// 创建一个OkHttpClient的实例
OkHttpClient client = new OkHttpClient();
//想要发起一条HTTP请求,就需要创建一个Request对象,可以在最终的build()之前连缀很多其他方法来丰富这个Request对象
Request request = new Request.Builder()
.url("http://www.baidu.com")
.build();
//调用OkHttpClient的newCall()方法来创建一个Call对象,并调用它的execute()方法来发送请求并获取服务器返回的数据
//response对象就是服务器返回的数据
Response response = client.newCall(request).execute();
//得到返回的具体内容
String responseData = response.body().string();
OkHttpClient ckient = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.build();
Call call = client.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 responseData = response.body().string();
Log.d(TAG, str);
}
});
//创建一个OKHttpClient实例
OkHttpClient client = new OkHttpClient();
//如果要发起Post请求,则需要先构建一个RequestBody对象存放待提交的参数
RequestBody requestBody = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build();
//然后在Request.Builder中调用一下post()方法,并将RequestBody对象传入
Request request = new Request.Builder()
.url("http://www.baidu.com")
.post(requestBody)
.build();
//调用execute()方法来发送请求并获取服务器返回的数据
Response response = client.newCall(request).execute();
//得到返回的具体内容
String responseData = response.body().string();
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.post(requestBody)
.build();
Call call = client.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 responseData = response.body().string();
Log.d(TAG, str);
}
});
注意:
在以上四段代码中,response.body().string()只能被调用一次,调用一次之后就会被释放,再次调用会爆:java.lang.IllegalStateException:closed
原因:调用一次之后它的内存就释放了
解决方法:可以把它赋值给一个String变量,然后多次使用!!
1、相较于Volley,它的最大并发量为64。
2、使用连接池技术,支持5个并发的socket连接默认keepAlive时间为5分钟,解决TCP握手和挥手的效率问题,减少握手次数
3、支持Gzip压缩,且操作对用户透明,可以通过header设置,在发起请求的时候自动加入header,Accept-Encoding: gzip,而我们的服务器返回的时候header中有Content-Encoding: gzip。
4、利用响应缓存来避免重复的网络请求。
5、很方便的添加拦截器,通常情况下,拦截器用来添加,移除,转换请求和响应的头部信息,比如添加公共参数等。
6、请求失败,自动重连,发生异常时重连。
7、支持SPDY协议。(SPDY是Google开发的基于TCP的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。新协议的功能包括数据流的多路复用、请求优先级以及HTTP报头压缩。谷歌表示,引入SPDY协议后,在实验室测试中页面加载速度比原先快64%)。
8、使用Okio来简化数据的访问与存储,提高性能。
1、消息回来需要切到主线程,主线程要自己去写。
2、调用比较复杂,需要自己进行封装。
3、缓存失效:网络请求时一般都会获取手机的一些硬件或网络信息,比如使用的网络环境。同时为了信息传输的安全性,可能还会对请求进行加密。在这些情况下OkHttp的缓存系统就会失效了,导致用户在无网络情况下不能访问缓存。
1、最明显的Builder设计模式,如构建对象OkHttpClient,还有单利模式
2、工厂方法模式,如源码中的接口Call
3、观察者模式如EventListener,监听请求和响应
4、策略模式
5、责任链模式,如拦截器
项目简介:采用OkHttp框架,通过访问聚合API查询手机归属地。
项目地址:https://github.com/ambition-hb/OkHttpDemo
项目图示:
部分代码如下:
/** * 采用OkHttp框架,通过访问聚合API查询手机归属地 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button sync_get;
private Button async_get;
private Button sync_post;
private Button async_post;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sync_get = (Button)findViewById(R.id.sync_get);
async_get = (Button)findViewById(R.id.async_get);
sync_post = (Button)findViewById(R.id.sync_post);
async_post = (Button)findViewById(R.id.async_post);
textView = (TextView)findViewById(R.id.tv);
sync_get.setOnClickListener(this);
async_get.setOnClickListener(this);
sync_post.setOnClickListener(this);
async_post.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.sync_get:
Sync_Get();
break;
case R.id.sync_post:
Sync_Post();
break;
case R.id.async_get:
Async_Get();
break;
case R.id.async_post:
Async_Post();
break;
default:
break;
}
}
//同步请求-GET
private void Sync_Get(){
//开启新线程来发起网络请求
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://apis.juhe.cn/mobile/get?phone=13429667914&key=fef8795fcfa0a1977582d8c31b529112")
.build();
Response response = null;//初始化
try {
response = client.newCall(request).execute();
String responseData = response.body().string();
showResponse(responseData);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
//异步请求-GET
private void Async_Get(){
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://apis.juhe.cn/mobile/get?phone=13956676914&key=fef8795fcfa0a1977582d8c31b529112")
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Toast.makeText(MainActivity.this, "异步网络请求(GET)失败!", Toast.LENGTH_SHORT).show();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseData = response.body().string();
showResponse(responseData);
}
});
}
}).start();
}
//同步请求-Post
private void Sync_Post(){
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("phone", "13852676914")
.add("key", "fef8795fcfa0a1977582d8c31b529112")
.build();
Request request = new Request.Builder()
.url("http://apis.juhe.cn/mobile/get?")
.post(requestBody)
.build();
Response response = null;//初始化
try {
response = client.newCall(request).execute();
String responseData = response.body().string();
showResponse(responseData);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
//异步请求-Post
private void Async_Post(){
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("phone", "13159476914")
.add("key", "fef8795fcfa0a1977582d8c31b529112")
.build();
Request request = new Request.Builder()
.url("http://apis.juhe.cn/mobile/get?")
.post(requestBody)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Toast.makeText(MainActivity.this, "异步网络请求(Post)失败!", Toast.LENGTH_SHORT).show();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseData = response.body().string();
showResponse(responseData);
}
});
}
}).start();
}
private void showResponse(final String response){
//Android不允许在子线程中进行UI操作
//通过该方法可以将线程切换到主线程,然后再更新UI元素
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(response);
}
});
}
}