Android学习笔记:OkHttp

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。

一、同步请求-GET

// 创建一个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();

二、异步请求-GET

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);
	}
});

三、同步请求-POST

//创建一个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();

四、异步请求-POST

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变量,然后多次使用!!

五、OkHttp的请求流程图

Android学习笔记:OkHttp_第1张图片

六、OkHttp的优点

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来简化数据的访问与存储,提高性能。

七、OkHttp的缺点

1、消息回来需要切到主线程,主线程要自己去写。
2、调用比较复杂,需要自己进行封装。
3、缓存失效:网络请求时一般都会获取手机的一些硬件或网络信息,比如使用的网络环境。同时为了信息传输的安全性,可能还会对请求进行加密。在这些情况下OkHttp的缓存系统就会失效了,导致用户在无网络情况下不能访问缓存。

八、OkHttp框架中都用到了哪些设计模式?

1、最明显的Builder设计模式,如构建对象OkHttpClient,还有单利模式
2、工厂方法模式,如源码中的接口Call
3、观察者模式如EventListener,监听请求和响应
4、策略模式
5、责任链模式,如拦截器

九、OkHttpDemo

项目简介:采用OkHttp框架,通过访问聚合API查询手机归属地。
项目地址:https://github.com/ambition-hb/OkHttpDemo
项目图示:
Android学习笔记:OkHttp_第2张图片

部分代码如下:

/** * 采用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);
            }
        });
    }
}

你可能感兴趣的:(Android,Android学习笔记)