简介

OkHttp 作为一个简洁高效的 HTTP 客户端,可以在 JavaAndroid 程序中使用。相对于 Apache HttpClient 来说,OkHttp 的性能更好,其 API 设计也更加简单实用。

Http Request

一个http requestRequest-line(请求行)Header(消息头)Message-body(请求实体)组成,后两者之间有一空行隔开,且后两者可以为空,而Request-line不得为空。

举个例子:

POST /index.php HTTP/1.1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0)
Accept: text/html
Accept-Language: zh-cn,zh;q=0.5
Referer: http://localhost/

第一行是请求行,指出了请求的方式为POST,访问的是根目录下的index.phphttp版本为1.1

余下的为消息头,包括user-agent(指明终端类型),accept(终端可以解释的类型),accept-language(浏览器能解释的语言)等等。

OkHttp库中,通过new Request.Builder().build()来创建Request对象,并且可以通过url()指定urlheader()指定消息头细节。

Get方式

实例化OkHttpClient

一般来说,一个app只需要一个OkHttpClient

OkHttpClient mClient = new OkHttpClient();

Sync get(同步get)

private void syncGet(String url) {
    final Request request = new Request.Builder()
            .url(url)
            .build();

    new Thread() {
        Response mResponse = null;
        @Override
        public void run() {
            super.run();
            try {
                mResponse = mClient.newCall(request).execute();
                System.out.println(mResponse.body().string());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }.start();
}

可以看到,Request通过Request.Builder().build()来生成。可以在生成过程中插入urlheader等。

同步方法相当于阻塞当前线程(UI线程),故需要开启子线程。通过OkHttpClient.newCall(request).execute()来访问网络。

Async get(异步get)

private void asyncGet(String url) {
    Request request = new Request.Builder()
            .url(url)
            .build();

    mClient.newCall(request).enqueue(mPrintResponseCallback);
}

异步方式,request的生成方式跟同步一样,但是执行使用的是enqueue方法。enqueue字眼说明了是进入线程调度,而不是直接阻塞当前线程。

enqueue方法需要传入一个Callback接口,这里自定义一个Callback接口:

private class printResponseCallback implements Callback {
    @Override
    public void onFailure(Call call, IOException e) {
        e.printStackTrace();
    }
    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (response.isSuccessful())
            System.out.println(response.body().string());
    }
}

需要重写两个方法,onFailure是访问失败时调用,onResponse是有Response返回时调用的方法,需要注意的是onResponse仍然是运行在工作线程,故不可以直接在此处更新UI

Post方式

Sync post(同步post)

private void syncPost(String url) {
    MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
    RequestBody requestBody = RequestBody.create(MEDIA_TYPE_TEXT, "Hello World");
    final Request request = new Request.Builder().url(url).post(requestBody).build();
    new Thread(){
        Response mResponse = null;
        @Override
        public void run() {
            super.run();
            try {
                mResponse = mClient.newCall(request).execute();
                System.out.println(mResponse.body().string());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }.start();
}

post请求需要指定MediaType,通过RequestBody.create(MediaType, String)可以将String类型转换成MediaType类型的RequestBody

在构建Request时,需要多加post(RequestBody)来添加请求实体。网络请求部分的代码跟get方式一样。

Async post(异步post)

private void asyncPost(String url) {
    MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
    RequestBody body = RequestBody.create(MEDIA_TYPE_TEXT, "Hello World");
    Request request = new Request.Builder().url(url).post(body).build();
    mClient.newCall(request).enqueue(mPrintResponseCallback);
}

流方式构建实体

private void postFlow(String url){
    final MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
    final String requestBody = "Hello World";
    RequestBody body = new RequestBody() {
        @Override
        public MediaType contentType() {
            return MEDIA_TYPE_TEXT;
        }
        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            sink.writeUtf8(requestBody);
        }
    };
    Request request = new Request.Builder().url(url).post(body).build();
    mClient.newCall(request).enqueue(mPrintResponseCallback);
}

这里创建了 RequestBody 的一个匿名子类。该子类的 contentType 方法需要返回内容的媒体类型,而 writeTo 方法的参数是一个 BufferedSink 对象。需要做的就是把请求的内容写入到 BufferedSink 对象。

Http Response

通过上述的几种方法我们都可以得到Response对象。

一个Http Response对象包括:Status-line、若干HeaderMessage-body,其中后两者可以没有,消息头和实体内容间有一个空行。

举个例子:

HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
Content-Length: 88
Content-Type: text/html
Connection: Closed

通过Response对象,使用response.body()可以获得message-body,通过request.headers可以得到集合对象Headers。利用headers.name(index)headers.value(index)可以分别得到每个header的名字和值。

总结

正在适应OkHttp