OkHttp3.0简单使用

前言

Android6.0移除了对HttpClient的支持,越来越多的应用开始使用Squre公司提供的开源框架OkHttp网络请求库,相对于以前的框架来说OkHttp有以下几大优点:

  • 允许连接到同一个主机地址的所有请求,提高请求效率
  • 共享Socket,减少对服务器的请求次数
  • 通过连接池,减少了请求延迟
  • 减少了对数据流量的消耗
  • 自动处理GZip压缩

使用OkHttp来做Android端的网络请求已经是大势所趋,现在就来简单的使用OkHttp提供的网络请求接口。

HTTP Get请求

开始网路请求之前一定要先创建Client对象,OkHttp提供了HttpUrl这个对象封装了请求url的各种配置,用户可以增加url后面的query参数,配置好HttpUrl之后调用它的构造者方法build就表示配置完成,接下来使用HttpUrl配置的请求链接生成Request对象,client方法会使用Request对象生成一个Call对象,如果执行execute方法代表在当前线程同步执行。

OkHttpClient client = new OkHttpClient();
HttpUrl httpUrl = HttpUrl.parse("https://api.heweather.com/x3/weather")
        .newBuilder()
        .addQueryParameter("city", "beijing")
        .addQueryParameter("key", "50f30154d0a94d87ba2611827da13200")
        .build();

System.out.println(httpUrl.toString());
Request request = new Request.Builder()
        .url(httpUrl.toString())
        .build();
try {
    Response response = client.newCall(request).execute();
    if (response.isSuccessful()) {
        System.out.println(response.body().string());
    }
} catch (IOException e) {
    e.printStackTrace();
}

在Android中如果在UI线程调用execute会阻塞主线程,这时候可以调用enqueue方法将请求假如到队列中由线程池异步执行,执行完成后再做回调操作。

public static void sendAsyncRequest(String url) {
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder().url(url).build();
    System.out.println(Thread.currentThread().getId());
    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (response.isSuccessful()) {
               System.out.println(Thread.currentThread().getId());
            }
        }
    });
}

HTTP POST请求

了解Web开发都知道Get请求只是使用url带参数来发起网络请求,Post请求的参数则是放在body当中,OkHttp里提供了RequestBody这个抽象类类来封装放在body中的请求参数值,其中有两个重要的子实现类分别是FormBody和MultiPartBody,前者主要提供类似于Html中的表单元素发起的Post请求,对body里的参数使用application/x-www-form-urlencoded方式的编码;后者通常采用multipart/form-data编码方式,使用与上传文件。这里先来看如何发起简单的post请求。

OkHttpClient client = new OkHttpClient();
FormBody body = new FormBody.Builder()
        .add("username", "zxz")
        .add("userage", String.valueOf(100))
        .build();
Request request = new Request.Builder()
    .url("http://127.0.0.1:8080/HelloServlet")
    .post(body)
    .build();
try {
    Response response = client.newCall(request).execute();
    if (response.isSuccessful()) {
        System.out.println(response.body().string());
    }
} catch (IOException e) {
    e.printStackTrace();
}

HTTP上传文件

前面的Post请求中已经提到上传文件使用multipart/form-data编码方式上传文件,在OkHttp里使用MultiPartBody来封装这样的请求实体对象。对于上传的图片要使用RequestBody的一个匿名内部类封装文件,指明要上传文件的MediaType类型和文件路径,将这个文件RequestBody放入MultipartBody中作为一个实体条目。除了构造网路请求的实体对象之外,其他的请求步骤都和普通的Post请求完全一致。

OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"),
        new File("/Users/zhangxingzhong/ic_launcher.png"));
MultipartBody body = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("filename", "ic_launcher.png", requestBody)
        .addFormDataPart("name", "zxz")
        .build();
Request request = new Request.Builder()
        .url("http://127.0.0.1:8080/UploadServlet")
        .post(body)
        .build();
try {
    Response response = okHttpClient.newCall(request).execute();
    if (response.isSuccessful()) {
        System.out.println(response.body().string());
    }
} catch (IOException e) {
    e.printStackTrace();
}

HTTP下载文件

OkHttp使用Request代表Http请求,使用Response对象来作为网络请求的响应结果,下载文件和Post请求类似不过返回的结果被作为输入流Response.body().byteStream()返回。普通的网络请求返回的是String字符串文本这时候可以采用Response.body().string()直接返回,如果返回的是特别长的文本或者是文件类型那么会突然分配大量的内存资源,这就是为什么通常文件都作为文件流返回。客户端得到下载文件的输入流之后就可以使用文件输出流保存Http请求到的文件数据。

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
    .url(url)
    .build();
okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        if (!response.isSuccessful())
            return;
        }

        File file = FileStorageManager.getInstance().getFileByName(url);
        byte[] buffer = new byte[1024 * 500];
        int len;
        FileOutputStream fos = new FileOutputStream(file);
        InputStream inputStream = response.body().byteStream();
        while((len = inputStream.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
            fos.flush();
        }
    }
});

请求头部和缓存

Http请求包含有大量的请求头内容,这些请求头通常包含了客户端的基础数据和对服务端的请求参数,OkHttp的Request请求对象在构建的时候就能够添加header键值对。

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
        .url("http://www.qq.com")
        .addHeader("User-Agent", "from OkHttp 3.0")
        .addHeader("Accept", "text/plain, text/html")
        .build();

try {
    Response response = client.newCall(request).execute();
    if (response.isSuccessful()) {
        Headers headers = response.headers();
        for (int i = 0; i < headers.size(); i++) {
            System.out.println(headers.name(i) + "=" + headers.value(i));
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}

除了上面的请求头设置,其实在网络请求的时候OkHttp还支持本地缓存对象,如果请求的结果还没有过期,那么OkHttp就不会再向服务器发起网络请求,而是直接使用本地的缓存内容,提高了Http的响应速度。

int maxCacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(new File("/Users/zhangxingzhong/test"), 
    maxCacheSize);
OkHttpClient client = new OkHttpClient.Builder()
    .cache(cache)
    .build();
Request request = new Request.Builder()
    .url("http://www.qq.com")
    .cacheControl(new CacheControl.Builder()
                            .noCache()
                            .build())
    .build();
Response response = client.newCall(request).execute();
response.body().string();
System.out.println("network response " + response.networkResponse());
System.out.println("cache response " + response.cacheResponse());

System.out.println("****************************");
Response response1 = client.newCall(request).execute();
response1.body().string();
System.out.println("network response " + response1.networkResponse());
System.out.println("cache response " + response1.cacheResponse());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值