开源框架OKHttp的使用01-基础

一、简介

Android系统提供了两种HTTP通信类,HttpURLConnection和HttpClient
尽管Google在大部分安卓版本中推荐使用HttpURLConnection,但是这个类相比HttpClient实在是太难用,太弱爆了。OkHttp是一个相对成熟的解决方案,据说Android4.4的源码中可以看到HttpURLConnection已经替换成OkHttp实现了。所以我们更有理由相信OkHttp的强大。使用时要求jdk及1.7以上。
下载:https://github.com/square/okhttp
okhttp内部依赖okio,需要同时导入okio
https://search.maven.org/remote_content?g=com.squareup.okio&a=okio&v=LATEST

也可以使用构建的方式进行导入,会自动从框架库中下载
MAVEN:

<dependency>
  <groupId>com.squareup.okhttp</groupId>
  <artifactId>okhttp</artifactId>
  <version>2.4.0</version>
</dependency>

GRADLE

compile 'com.squareup.okhttp:okhttp:2.4.0'

二、使用场景

一般的get请求
一般的post请求
基于Http的文件上传
文件下载
加载图片
支持请求回调,直接返回对象、对象集合
支持session的保持

三、使用示例

okhttp网络请求分为同步请求和异步请求。
异步请求执行方法:

Call call = client.newCall(request);
call.enqueue(new Callback(){...});

异步请求数据示例

private void okhttpA(String url) {
        // 1.需要一个OkHttpClient对象,最好一个app中只实例化一个该对象。
        OkHttpClient client = new OkHttpClient();
        // 2.新建一个请求
        Request request = new Request.Builder().url(url).build();
        // 3.执行请求,获得响应的结果
        Call call = client.newCall(request);
        // 4.加入调度
        final TextView tv = new TextView(this);
        call.enqueue(new Callback() {

            @Override
            public void onResponse(Response response) throws IOException {
                if (response.isSuccessful()) {
                    final String str = response.body().string();
                    runOnUiThread( new Runnable() {
                        public void run() {
                            tv.setText(str);
                        }
                    });
                } else {
                    throw new IOException("Unexpected code " + response);
                }
            }
            @Override
            public void onFailure(Request arg0, IOException arg1) {

            }
        });
    }

同步请求执行方法:

Call call = client.newCall(request);
call.execute();

同步请求数据示例

private String okhttpB(String url) throws IOException {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        Call call = client.newCall(request);
        Response response = call.execute();
        if (response.isSuccessful()) {
            return response.body().string();
        } else {
            throw new IOException("Unexpected code " + response);
        }
    }

下面主要示例都以异步为主:
1.一般的get请求

    private void okhttpGet(String url){
        //1.需要一个OkHttpClient对象,最好一个app中只实例化一个该对象。
        OkHttpClient client = new OkHttpClient();
        //2.新建一个请求
        Request request = new Request.Builder().url(url).build();
        //3.执行请求,获得响应的结果
        Call call = client.newCall(request);
        //4.加入调度
        call.enqueue(new Callback() {

            @Override
            public void onResponse(Response arg0) throws IOException {
                // TODO Auto-generated method stub

            }
            @Override
            public void onFailure(Request arg0, IOException arg1) {
                // TODO Auto-generated method stub

            }
        });
    }

2.post提交,提交各种类型数据
这种提交形式和服务器有关,有些服务器不支持这种数据处理。

①提交json类型字符串

public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private void okhttpPostWithJson(String url)  {
        String json ="";    //一个Json字符串
        // 1.创建OkHttpClient
        OkHttpClient client = new OkHttpClient();
        // 2.新建请求体,放入参数
        RequestBody body = RequestBody.create(JSON, json);
        // 3.新建请求
        Request request = new Request.Builder().url(url).post(body).build();
        // 4.new call
        Call call = client.newCall(request);
        //5.监听回调
        call.enqueue(new Callback() {

            @Override
            public void onResponse(Response arg0) throws IOException {
                // TODO Auto-generated method stub

            }

            @Override
            public void onFailure(Request arg0, IOException arg1) {
                // TODO Auto-generated method stub

            }
        });
    }

②这个例子提交了一个markdown文档到web服务,以HTML方式渲染markdown。因为整个请求体都在内存中,因此避免使用此api提交大文档(大于1MB)。

    public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
    private final OkHttpClient client = new OkHttpClient();
    public void run() throws Exception {
        String postBody = ""
            + "Releases\n"
            + "--------\n"
            + "\n"
            + " * _1.0_ May 6, 2013\n"
            + " * _1.1_ June 15, 2013\n"
            + " * _1.2_ August 11, 2013\n";

        Request request = new Request.Builder()
            .url("https://api.github.com/markdown/raw")
            .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
            .build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
        System.out.println(response.body().string());
    }

③使用流的方式,POST提交请求体。请求体的内容(也就是携带的数据体)由流写入产生。这个例子是流直接写入Okio的BufferedSink。你的程序可能会使用OutputStream,你可以使用BufferedSink.outputStream()来获取一个OutputStream实例。

public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
    private final OkHttpClient client = new OkHttpClient();

    public void okhttpPostStream() throws Exception {
        //1.携带的数据体
        RequestBody requestBody = new RequestBody() {
            //文件类型
            @Override
            public MediaType contentType() {
                return MEDIA_TYPE_MARKDOWN;
            }
            //写入的数据内容
            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                sink.writeUtf8("Numbers\n");
                sink.writeUtf8("-------\n");
                for (int i = 2; i <= 997; i++) {
                    sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
                }
            }

            private String factor(int n) {
                for (int i = 2; i < n; i++) {
                    int x = n / i;
                    if (x * i == n)
                        return factor(x) + " × " + i;
                }
                return Integer.toString(n);
            }
        };

        //2.请求体
        Request request = new Request.Builder()
                .url("https://api.github.com/markdown/raw")
                .post(requestBody)
                .build();
        //3.执行请求,获得返回结果
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful())
            throw new IOException("Unexpected code " + response);
        System.out.println(response.body().string());
    }

④上传一个本地文件

public static final MediaType MEDIA_TYPE_MARKDOWN= MediaType.parse("text/x-markdown; charset=utf-8");
    private final OkHttpClient client = new OkHttpClient();
    public void okhttpPostFile() throws Exception {

        File file = null;
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            //sd卡不存在
            return;
        }
        file = new File(Environment.getExternalStorageDirectory()+"/readme.txt");
        if(!file.exists()){
            //文件不存在
            return;
        }
        Request request = new Request.Builder()
            .url("https://api.github.com/markdown/raw")
            .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
            .build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

        System.out.println(response.body().string());
    }

3.post提交,参数为键值对

private void okhttpPostWithParams(String url) throws IOException {
        OkHttpClient client = new OkHttpClient();
        RequestBody body = new FormEncodingBuilder()
                .add("id", "154")
                .add("name", "Jack")
                .add("password", "123456")
                .build();
        Request request = new Request.Builder()
            .url(url)
            .post(body)
            .build();

        Call call = client.newCall(request);
        call.enqueue(new Callback() {

            @Override
            public void onResponse(Response arg0) throws IOException {
                // TODO Auto-generated method stub

            }

            @Override
            public void onFailure(Request arg0, IOException arg1) {
                // TODO Auto-generated method stub

            }
        });
    }

4.提取响应头信息

private final OkHttpClient client = new OkHttpClient();
    public void okhttpGetHeader() throws Exception {
        Request request = new Request.Builder()
            .url("https://api.github.com/repos/square/okhttp/issues")
            .header("User-Agent", "OkHttp Headers.java")
            .addHeader("Accept", "application/json; q=0.5")
            .addHeader("Accept", "application/vnd.github.v3+json")
            .build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

        System.out.println("Server: " + response.header("Server"));
        System.out.println("Date: " + response.header("Date"));
        System.out.println("Vary: " + response.headers("Vary"));
    }

5post提交分块请求
MultipartBuilder可以构建复杂的请求体,与HTML文件上传形式兼容。多块请求体中每块请求都是一个请求体,可以定义自己的请求头。这些请求头可以用来描述这块请求,例如他的Content-Disposition。如果Content-Length和Content-Type可用的话,他们会被自动添加到请求头中。

private static final String IMGUR_CLIENT_ID = "...";
    private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
    private final OkHttpClient client = new OkHttpClient();

    public void okhttpPostMultipart() throws Exception {
        // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
        RequestBody requestBody = new MultipartBuilder()
            .type(MultipartBuilder.FORM)
            .addPart(
                Headers.of("Content-Disposition", "form-data; name=\"title\""),
                RequestBody.create(null, "Square Logo"))
            .addPart(
                Headers.of("Content-Disposition", "form-data; name=\"image\""),
                RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
            .build();

        Request request = new Request.Builder()
            .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
            .url("https://api.imgur.com/3/image")
            .post(requestBody)
            .build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
        System.out.println(response.body().string());
    }

6.使用Gson来解析JSON响应
Gson是一个在JSON和Java对象之间转换非常方便的api。这里我们用Gson来解析JSON响应。
注意:ResponseBody.charStream()使用响应头Content-Type指定的字符集来解析响应体。默认是UTF-8。

private final OkHttpClient client = new OkHttpClient();
    private final Gson gson = new Gson();

    public void run() throws Exception {
        Request request = new Request.Builder()
            .url("https://api.github.com/gists/c2a7c39532239ff261be")
            .build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

        Gist gist = gson.fromJson(response.body().charStream(), Gist.class);
        Set<Entry<String, GistFile>> entrySet =  gist.files.entrySet();
        for(Entry<String, GistFile> entry:entrySet){
             System.out.println(entry.getKey());
             System.out.println(entry.getValue().content);
        }
    }

    static class Gist {
        Map<String, GistFile> files;
    }

    static class GistFile {
        String content;
    }

7.图片下载

     byte[] data = response.body().bytes();
     Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);

8.文件下载

     InputStream is = response.body().byteStream();
     byte[] buffer = new byte[1024];

     File file = new File(Environment.getExternalStorageDirectory(), "aa.mp3");
     FileOutputStream fos = new FileOutputStream(file);
     while( (is.read(buffer)) != -1 ){
        fos.write(buffer, 0, buffer.length);
        fos.flush();
     }
     is.close();
     fos.close();

9.其他
①取消一个call

 call.cancel();

②设置超时时间

    client = new OkHttpClient();
    client.setConnectTimeout(10, TimeUnit.SECONDS);
    client.setWriteTimeout(10, TimeUnit.SECONDS);
    client.setReadTimeout(30, TimeUnit.SECONDS);

③克隆一个client,基本配置和原来的一样,但是我们可以在克隆之后的client进行修改。

    private final OkHttpClient client = new OkHttpClient();
    public void okhttpClone(){
        Request request = new Request.Builder()
            .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay.
            .build();
        //克隆OkHttpClient
        try {
            OkHttpClient client1 = client.clone();
            client1.setReadTimeout(500, TimeUnit.MICROSECONDS);
            Call call1 = client1.newCall(request);
            Response response1;
            response1 = call1.execute();
            System.out.println("Response 1 succeeded: " + response1);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Response 1 failed: " + e);
        }

        try {
            OkHttpClient client2 = client.clone();
            client2.setReadTimeout(3000, TimeUnit.MICROSECONDS);
            Call call2 = client2.newCall(request);
            Response response2;
            response2 = call2.execute();
            System.out.println("Response 2 succeeded: " + response2);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Response 2 failed: " + e);
        }
    }

参考文章:http://www.cnblogs.com/ct2011/p/3997368.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值