okhttp 订阅
android网络框架之OKhttp一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso) [1]  用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient,现在已经打不出来) 展开全文
android网络框架之OKhttp一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso) [1]  用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient,现在已经打不出来)
信息
适用平台
android
是否开源
作    用
应用广泛的Android网络框架
中文名
okhttp
外文名
okhttp
作    者
Square公司
okhttp优势
允许连接到同一个主机地址的所有请求,提高请求效率 [2]  共享Socket,减少对服务器的请求次数 [2]  通过连接池,减少了请求延迟 [2]  缓存响应数据来减少重复的网络请求 [3]  减少了对数据流量的消耗 [2]  自动处理GZip压缩 [2] 
收起全文
精华内容
参与话题
问答
  • OkHttp使用详解

    千次阅读 2016-12-18 18:04:33
    今天学习了一下OkHttp,在这里做个总结,希望可以帮助到有需要的人,好了,废话不多说,进入正题。

    今天学习了一下OkHttp,在这里做个总结,希望可以帮助到有需要的人,好了,废话不多说,进入正题。

    一、OkHttp介绍

    OkHttp是一个优秀的网络请求框架,可能一说到网络请求框架,可能很多人都会想到volley,volley是一个Google提供的网络请求框架,我的博客里也有一篇专门介绍volley的博客,博客地址在此Volley的使用 那么既然Google提供了网络请求的框架,我们为什么还要使用OkHttp呢,原来是volley是要依靠HttpCient的,而Google在Android6.0的SDK中去掉了HttpCient,所以OkHttp就开始越来越受大家的欢迎.

    今天我们主要介绍OkHttpGet请求、Post请求、上传下载文件上传下载图片等功能

    当然在开始之前,我们还要先在项目中添加OkHttp的依赖库,至于怎么在AndroidStudio中给项目添加OkHTTP依赖,这里将不再赘述。另外,OkHttp中使用了建造者模式,如果对建造者模式不了解,可以看看这篇博客设计模式之建造者模式

    添加OkHttp的依赖

    在对应的Module的gradle中添加
    compile 'com.squareup.okhttp3:okhttp:3.5.0'   
    然后同步一下项目即可

    二、OkHttp进行Get请求

    使用OkHttp进行Get请求只需要四步即可完成。

    1 . 拿到OkHttpClient对象

    OkHttpClient client = new OkHttpClient();

    2 . 构造Request对象

    Request request = new Request.Builder()
                    .get()
                    .url("https://www.baidu.com")
                    .build();

    这里我们采用建造者模式和链式调用指明是进行Get请求,并传入Get请求的地址

    如果我们需要在get请求时传递参数,我们可以以下面的方式将参数拼接在url之后

    https:www.baidu.com?username=admin&password=admin

    3 . 将Request封装为Call

    Call call = client.newCall(request);

    4 . 根据需要调用同步或者异步请求方法

    //同步调用,返回Response,会抛出IO异常
    Response response = call.execute();
    
    //异步调用,并设置回调函数
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Toast.makeText(OkHttpActivity.this, "get failed", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onResponse(Call call, final Response response) throws IOException {
            final String res = response.body().string();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    contentTv.setText(res);
                }
            });
        }
    });

    第四步有一些需要注意的地方
    1. 同步调用会阻塞主线程,一般不适用
    2. 异步调用的回调函数是在子线程,我们不能在子线程更新UI,需要借助于runOnUiThread()方法或者Handler来处理

    是不是以为上面就结束了,对的,OkHttp的Get请求步骤就这么4步,但是当你试图打开应用加载数据,可是发现并没有加载到数据,这是一个简单但是我们常犯的错误.
    在AndroidManifest.xml中加入联网权限

    <uses-permission android:name="android.permission.INTERNET" />

    三、OkHttp进行Post请求提交键值对

    使用OkHttp进行Post请求和进行Get请求很类似,只需要五步即可完成。

    1 . 拿到OkHttpClient对象

    OkHttpClient client = new OkHttpClient();

    2 . 构建FormBody,传入参数

    FormBody formBody = new FormBody.Builder()
                    .add("username", "admin")
                    .add("password", "admin")
                    .build();

    3 . 构建Request,将FormBody作为Post方法的参数传入

    final Request request = new Request.Builder()
                    .url("http://www.jianshu.com/")
                    .post(formBody)
                    .build();

    4 . 将Request封装为Call

    Call call = client.newCall(request);

    5 . 调用请求,重写回调方法

    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Toast.makeText(OkHttpActivity.this, "Post Failed", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            final String res = response.body().string();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    contentTv.setText(res);
                }
            });
        }
    });

    经过上面的步骤一个post请求就完成了,当然上面的url参数和需要传入的参数大家就要根据实际情况来传入,你会发现get和post请求的步骤非常像。

    四、OkHttp进行Post请求提交字符串

    如果你已经掌握了上面的两种基本的步骤,那下面的内容就比较简单了

    上面我们的post的参数是通过构造一个FormBody通过键值对的方式来添加进去的,其实post方法需要传入的是一个RequestBody对象,FormBodyRequestBody的子类,但有时候我们常常会遇到要传入一个字符串的需求,比如客户端给服务器发送一个json字符串,那这种时候就需要用到另一种方式来构造一个RequestBody如下所示:

    RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), "{username:admin;password:admin}");

    上面的MediaType我们指定传输的是纯文本,而且编码方式是utf-8,通过上面的方式我们就可以向服务端发送json字符串啦。

    注:关于MidiaType的类型你可以百度搜索mime type查看相关的内容,这里不再赘述

    五、OkHttp进行Post请求上传文件

    理解了上面一个,下面这个就更简单了,这里我们以上传一张图片为例,当然你也可以上传一个txt什么的文件,都是可以的

    其实最主要的还是构架我们自己的RequestBody,如下图构建

    File file = new File(Environment.getExternalStorageDirectory(), "1.png");
    if (!file.exists()){
        Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show();
    }else{
        RequestBody requestBody2 = RequestBody.create(MediaType.parse("application/octet-stream"), file);
    }

    这里我们将手机SD卡根目录下的1.png图片进行上传。代码中的application/octet-stream表示我们的文件是任意二进制数据流,当然你也可以换成更具体的image/png

    注:最后记得最重要的一点:添加存储卡写权限,在AndroidManifest.xml文件中添加如下代码:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    六、OkHttp进行Post请求提交表单

    我们在网页上经常会遇到用户注册的情况,需要你输入用户名,密码,还有上传头像,这其实就是一个表单,那么接下来我们看看如何利用OkHttp来进行表单提交。经过上面的学习,大家肯定也懂,主要的区别就在于构造不同的RequestBody传递给post方法即可.

    由于我们使用的是OkHttp3所以我们还需要再导入一个包okio.jar才能继续下面的内容,我们需要在模块的Gradle文件中添加如下代码,然后同步一下项目即可

    compile 'com.squareup.okio:okio:1.11.0'

    这里我们会用到一个MuiltipartBody,这是RequestBody的一个子类,我们提交表单就是利用这个类来构建一个RequestBody,下面的代码我们会发送一个包含用户民、密码、头像的表单到服务端

    File file = new File(Environment.getExternalStorageDirectory(), "1.png");
    if (!file.exists()){
        Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show();
        return;
    }
    RequestBody muiltipartBody = new MultipartBody.Builder()
            //一定要设置这句
            .setType(MultipartBody.FORM)
            .addFormDataPart("username", "admin")//
            .addFormDataPart("password", "admin")//
            .addFormDataPart("myfile", "1.png", RequestBody.create(MediaType.parse("application/octet-stream"), file))
            .build();

    上面添加用户民和密码的部分和我们上面学习的提交键值对的方法很像,我们关键要注意以下几点:

    (1)如果提交的是表单,一定要设置setType(MultipartBody.FORM)这一句

    (2)提交的文件addFormDataPart()的第一个参数,就上面代码中的myfile就是类似于键值对的键,是供服务端使用的,就类似于网页表单里面的name属性,例如下面:

    <input type="file" name="myfile">

    (3)提交的文件addFormDataPart()的第二个参数文件的本地的名字,第三个参数是RequestBody,里面包含了我们要上传的文件的路径以及MidiaType

    (4)记得在AndroidManifest.xml文件中添加存储卡读写权限

    七、OkHttp进行get请求下载文件

    除了上面的功能,我们最常用的功能该有从网路上下载文件,我们下面的例子将演示下载一个文件存放在存储卡根目录,从网络下载一张图片并显示到ImageView中

    1 . 从网络下载一个文件(此处我们以下载一张图片为例)

    public void downloadImg(View view){
        OkHttpClient client = new OkHttpClient();
        final Request request = new Request.Builder()
                .get()
                .url("https://www.baidu.com/img/bd_logo1.png")
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e("moer", "onFailure: ");;
            }
    
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //拿到字节流
                InputStream is = response.body().byteStream();
    
                int len = 0;
                File file  = new File(Environment.getExternalStorageDirectory(), "n.png");
                FileOutputStream fos = new FileOutputStream(file);
                byte[] buf = new byte[128];
    
                while ((len = is.read(buf)) != -1){
                    fos.write(buf, 0, len);
                }
    
                fos.flush();
                //关闭流
                fos.close();
                is.close();
            }
        });
    }

    你会发现步骤与进行一般的Get请求差别不大,唯一的区别在于我们在回调函数中所做的事,我们拿到了图片的字节流,然后保存为了本地的一张图片

    2 . 从网络下载一张图片并设置到ImageView中

    其实学会了上面的步骤你完全可以将图片下载到本地后再设置到ImageView中,当然下面是另一种方法
    这里我们使用BitmapFactorydecodeStream将图片的输入流直接转换为Bitmap,然后设置到ImageView中,下面只给出onResponse()中的代码.

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        InputStream is = response.body().byteStream();
    
        final Bitmap bitmap = BitmapFactory.decodeStream(is);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                imageView.setImageBitmap(bitmap);
            }
        });
    
        is.close();
    }

    八、给文件的上传和下载加上进度条

    我们一直都说,用户体验很重要,当我们下载的文件比较大,而网速又比较慢的时候,如果我们只是在后台下载或上传,没有给用户显示一个进度,那将是非常差的用户体验,下面我们就将简单做一下进度的显示,其实非常简单的

    1 . 显示文件下载进度

    这里只是演示,我只是把进度显示在一个TextView中,至于进度的获取当然是在我们的回调函数onResponse()中去获取

    (1)使用response.body().contentLength()拿到文件总大小

    (2)在while循环中每次递增我们读取的buf的长度

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        InputStream is = response.body().byteStream();
        long sum = 0L;
        //文件总大小
        final long total = response.body().contentLength();
        int len = 0;
        File file  = new File(Environment.getExternalStorageDirectory(), "n.png");
        FileOutputStream fos = new FileOutputStream(file);
        byte[] buf = new byte[128];
    
        while ((len = is.read(buf)) != -1){
            fos.write(buf, 0, len);
            //每次递增
            sum += len;
    
            final long finalSum = sum;
            Log.d("xh1", "onResponse: " + finalSum + "/" + total);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //将进度设置到TextView中
                    contentTv.setText(finalSum + "/" + total);
                }
            });
        }
        fos.flush();
        fos.close();
        is.close();
    }

    2 . 显示文件上传进度

    对于上传的进度的处理会比较麻烦,因为具体的上传过程是在RequestBody中由OkHttp帮我们处理上传,而且OkHttp并没有给我们提供上传进度的接口,这里我们的做法是自定义类继承RequestBody,然后重写其中的方法,将其中的上传进度通过接口回调暴露出来供我们使用。

    public class CountingRequestBody extends RequestBody {
        //实际起作用的RequestBody
        private RequestBody delegate;
        //回调监听
        private Listener listener;
    
        private CountingSink countingSink;
    
        /**
         * 构造函数初始化成员变量
         * @param delegate
         * @param listener
         */
        public CountingRequestBody(RequestBody delegate, Listener listener){
            this.delegate = delegate;
            this.listener = listener;
        }
        @Override
        public MediaType contentType() {
            return delegate.contentType();
        }
    
        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            countingSink = new CountingSink(sink);
            //将CountingSink转化为BufferedSink供writeTo()使用
            BufferedSink bufferedSink = Okio.buffer(countingSink);
            delegate.writeTo(bufferedSink);
            bufferedSink.flush();
        }
    
        protected final class CountingSink extends ForwardingSink{
            private long byteWritten;
            public CountingSink(Sink delegate) {
                super(delegate);
            }
    
            /**
             * 上传时调用该方法,在其中调用回调函数将上传进度暴露出去,该方法提供了缓冲区的自己大小
             * @param source
             * @param byteCount
             * @throws IOException
             */
            @Override
            public void write(Buffer source, long byteCount) throws IOException {
                super.write(source, byteCount);
                byteWritten += byteCount;
                listener.onRequestProgress(byteWritten, contentLength());
            }
        }
    
        /**
         * 返回文件总的字节大小
         * 如果文件大小获取失败则返回-1
         * @return
         */
        @Override
        public long contentLength(){
            try {
                return delegate.contentLength();
            } catch (IOException e) {
                return -1;
            }
        }
    
        /**
         * 回调监听接口
         */
        public static interface Listener{
            /**
             * 暴露出上传进度
             * @param byteWritted  已经上传的字节大小
             * @param contentLength 文件的总字节大小
             */
            void onRequestProgress(long byteWritted, long contentLength);
        }
    }

    上面的代码注释非常详细,这里不再解释,然后我们在写具体的请求时还需要做如下变化

    File file = new File(Environment.getExternalStorageDirectory(), "1.png");
    if (!file.exists()){
        Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show();
    }else{
        RequestBody requestBody2 = RequestBody.create(MediaType.parse("application/octet-stream"), file);
    }
    
    //使用我们自己封装的类
    CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody2, new CountingRequestBody.Listener() {
        @Override
        public void onRequestProgress(long byteWritted, long contentLength) {
            //打印进度
            Log.d("xh", "进度 :" + byteWritted + "/" + contentLength);
        }
    });

    上面其实就是在原有的RequestBody上包装了一层,最后在我们的使用中在post()方法中传入我们的CountingRequestBody对象即可。

    九、后记

    以上就是一些OkHttp常用的总结,希望可以帮助到需要的人

    展开全文
  • Android OkHttp完全解析 是时候来了解OkHttp

    万次阅读 多人点赞 2015-08-24 15:36:45
    转载请标明出处: ...最近在群里听到各种讨论okhttp的话题,可见okhttp的口碑相当好了。再加上Google貌似在6.0版本里面删除了HttpClient相关API,对于这个行为不做评价。为了更好的在应对网络访问,学习

    转载请标明出处:
    http://blog.csdn.net/lmj623565791/article/details/47911083
    本文出自:【张鸿洋的博客】

    一、概述

    最近在群里听到各种讨论okhttp的话题,可见okhttp的口碑相当好了。再加上Google貌似在6.0版本里面删除了HttpClient相关API,对于这个行为不做评价。为了更好的在应对网络访问,学习下okhttp还是蛮必要的,本篇博客首先介绍okhttp的简单使用,主要包含:

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

    最后会对上述几个功能进行封装,完整的封装类的地址见:https://github.com/hongyangAndroid/okhttp-utils

    使用前,对于Android Studio的用户,可以选择添加:

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

    或者Eclipse的用户,可以下载最新的jar okhttp he latest JAR ,添加依赖就可以用了。

    注意:okhttp内部依赖okio,别忘了同时导入okio:

    gradle: compile 'com.squareup.okio:okio:1.5.0'

    最新的jar地址:okio the latest JAR


    二、使用教程

    (一)Http Get

    对了网络加载库,那么最常见的肯定就是http get请求了,比如获取一个网页的内容。

    //创建okHttpClient对象
    OkHttpClient mOkHttpClient = new OkHttpClient();
    //创建一个Request
    final Request request = new Request.Builder()
                    .url("https://github.com/hongyangAndroid")
                    .build();
    //new call
    Call call = mOkHttpClient.newCall(request); 
    //请求加入调度
    call.enqueue(new Callback()
            {
                @Override
                public void onFailure(Request request, IOException e)
                {
                }
    
                @Override
                public void onResponse(final Response response) throws IOException
                {
                        //String htmlStr =  response.body().string();
                }
            });             
    
    
    1. 以上就是发送一个get请求的步骤,首先构造一个Request对象,参数最起码有个url,当然你可以通过Request.Builder设置更多的参数比如:headermethod等。

    2. 然后通过request的对象去构造得到一个Call对象,类似于将你的请求封装成了任务,既然是任务,就会有execute()cancel()等方法。

    3. 最后,我们希望以异步的方式去执行请求,所以我们调用的是call.enqueue,将call加入调度队列,然后等待任务执行完成,我们在Callback中即可得到结果。

    看到这,你会发现,整体的写法还是比较长的,所以封装肯定是要做的,不然每个请求这么写,得累死。

    ok,需要注意几点:

    • onResponse回调的参数是response,一般情况下,比如我们希望获得返回的字符串,可以通过response.body().string()获取;如果希望获得返回的二进制字节数组,则调用response.body().bytes();如果你想拿到返回的inputStream,则调用response.body().byteStream()

      看到这,你可能会奇怪,竟然还能拿到返回的inputStream,看到这个最起码能意识到一点,这里支持大文件下载,有inputStream我们就可以通过IO的方式写文件。不过也说明一个问题,这个onResponse执行的线程并不是UI线程。的确是的,如果你希望操作控件,还是需要使用handler等,例如:

      @Override
      public void onResponse(final Response response) throws IOException
      {
            final String res = response.body().string();
            runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                  mTv.setText(res);
                }
      
            });
      }
    • 我们这里是异步的方式去执行,当然也支持阻塞的方式,上面我们也说了Call有一个execute()方法,你也可以直接调用call.execute()通过返回一个Response

    (二) Http Post 携带参数

    看来上面的简单的get请求,基本上整个的用法也就掌握了,比如post携带参数,也仅仅是Request的构造的不同。

    Request request = buildMultipartFormRequest(
            url, new File[]{file}, new String[]{fileKey}, null);
    FormEncodingBuilder builder = new FormEncodingBuilder();   
    builder.add("username","张鸿洋");
    
    Request request = new Request.Builder()
                       .url(url)
                    .post(builder.build())
                    .build();
     mOkHttpClient.newCall(request).enqueue(new Callback(){});

    大家都清楚,post的时候,参数是包含在请求体中的;所以我们通过FormEncodingBuilder。添加多个String键值对,然后去构造RequestBody,最后完成我们Request的构造。

    后面的就和上面一样了。


    (三)基于Http的文件上传

    接下来我们在介绍一个可以构造RequestBody的Builder,叫做MultipartBuilder。当我们需要做类似于表单上传的时候,就可以使用它来构造我们的requestBody。

    File file = new File(Environment.getExternalStorageDirectory(), "balabala.mp4");
    
    RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
    
    RequestBody requestBody = new MultipartBuilder()
         .type(MultipartBuilder.FORM)
         .addPart(Headers.of(
              "Content-Disposition", 
                  "form-data; name=\"username\""), 
              RequestBody.create(null, "张鸿洋"))
         .addPart(Headers.of(
             "Content-Disposition", 
             "form-data; name=\"mFile\"; 
             filename=\"wjd.mp4\""), fileBody)
         .build();
    
    Request request = new Request.Builder()
        .url("http://192.168.1.103:8080/okHttpServer/fileUpload")
        .post(requestBody)
        .build();
    
    Call call = mOkHttpClient.newCall(request);
    call.enqueue(new Callback()
    {
        //...
    });

    上述代码向服务器传递了一个键值对username:张鸿洋和一个文件。我们通过MultipartBuilder的addPart方法可以添加键值对或者文件。

    其实类似于我们拼接模拟浏览器行为的方式,如果你对这块不了解,可以参考:从原理角度解析Android (Java) http 文件上传

    ok,对于我们最开始的目录还剩下图片下载,文件下载;这两个一个是通过回调的Response拿到byte[]然后decode成图片;文件下载,就是拿到inputStream做写文件操作,我们这里就不赘述了。

    关于用法,也可以参考泡网OkHttp使用教程

    接下来我们主要看如何封装上述的代码。


    三、封装

    由于按照上述的代码,写多个请求肯定包含大量的重复代码,所以我希望封装后的代码调用是这样的:

    (一)使用

    1. 一般的get请求

       OkHttpClientManager.getAsyn("https://www.baidu.com", new OkHttpClientManager.ResultCallback<String>()
              {
                  @Override
                  public void onError(Request request, Exception e)
                  {
                      e.printStackTrace();
                  }
      
                  @Override
                  public void onResponse(String u)
                  {
                      mTv.setText(u);//注意这里是UI线程
                  }
              });

      对于一般的请求,我们希望给个url,然后CallBack里面直接操作控件。

    2. 文件上传且携带参数

      我们希望提供一个方法,传入url,params,file,callback即可。

        OkHttpClientManager.postAsyn("http://192.168.1.103:8080/okHttpServer/fileUpload",//
          new OkHttpClientManager.ResultCallback<String>()
          {
              @Override
              public void onError(Request request, IOException e)
              {
                  e.printStackTrace();
              }
      
              @Override
              public void onResponse(String result)
              {
      
              }
          },//
          file,//
          "mFile",//
          new OkHttpClientManager.Param[]{
                  new OkHttpClientManager.Param("username", "zhy"),
                  new OkHttpClientManager.Param("password", "123")}
              );
      

      键值对没什么说的,参数3为file,参数4为file对应的name,这个name不是文件的名字;
      对应于http中的

      <input type="file" name="mFile" >

      对应的是name后面的值,即mFile.

    3. 文件下载

      对于文件下载,提供url,目标dir,callback即可。

      OkHttpClientManager.downloadAsyn(
          "http://192.168.1.103:8080/okHttpServer/files/messenger_01.png",    
          Environment.getExternalStorageDirectory().getAbsolutePath(), 
      new OkHttpClientManager.ResultCallback<String>()
          {
              @Override
              public void onError(Request request, IOException e)
              {
      
              }
      
              @Override
              public void onResponse(String response)
              {
                  //文件下载成功,这里回调的reponse为文件的absolutePath
              }
      });
    4. 展示图片

      展示图片,我们希望提供一个url和一个imageview,如果下载成功,直接帮我们设置上即可。

       OkHttpClientManager.displayImage(mImageView, 
           "http://images.csdn.net/20150817/1.jpg");

      内部会自动根据imageview的大小自动对图片进行合适的压缩。虽然,这里可能不适合一次性加载大量图片的场景,但是对于app中偶尔有几个图片的加载,还是可用的。


    四、整合Gson

    很多人提出项目中使用时,服务端返回的是Json字符串,希望客户端回调可以直接拿到对象,于是整合进入了Gson,完善该功能。

    (一)直接回调对象

    例如现在有个User实体类:

    package com.zhy.utils.http.okhttp;
    
    public class User {
    
        public String username ; 
        public String password  ;
    
        public User() {
            // TODO Auto-generated constructor stub
        }
    
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
    
        @Override
        public String toString()
        {
            return "User{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }

    服务端返回:

    {"username":"zhy","password":"123"}

    客户端可以如下方式调用:

     OkHttpClientManager.getAsyn("http://192.168.56.1:8080/okHttpServer/user!getUser",
    new OkHttpClientManager.ResultCallback<User>()
    {
        @Override
        public void onError(Request request, Exception e)
        {
            e.printStackTrace();
        }
    
        @Override
        public void onResponse(User user)
        {
            mTv.setText(u.toString());//UI线程
        }
    });

    我们传入泛型User,在onResponse里面直接回调User对象。
    这里特别要注意的事,如果在json字符串->实体对象过程中发生错误,程序不会崩溃,onError方法会被回调。

    注意:这里做了少许的更新,接口命名从StringCallback修改为ResultCallback。接口中的onFailure方法修改为onError

    (二) 回调对象集合

    依然是上述的User类,服务端返回

    [{"username":"zhy","password":"123"},{"username":"lmj","password":"12345"}]

    则客户端可以如下调用:

    OkHttpClientManager.getAsyn("http://192.168.56.1:8080/okHttpServer/user!getUsers",
    new OkHttpClientManager.ResultCallback<List<User>>()
    {
        @Override
        public void onError(Request request, Exception e)
        {
            e.printStackTrace();
        }
        @Override
        public void onResponse(List<User> us)
        {
            Log.e("TAG", us.size() + "");
            mTv.setText(us.get(1).toString());
        }
    });

    唯一的区别,就是泛型变为List<User> ,ok , 如果发现bug或者有任何意见欢迎留言。


    源码

    ok,基本介绍完了,对于封装的代码其实也很简单,我就直接贴出来了,因为也没什么好介绍的,如果你看完上面的用法,肯定可以看懂:

    package com.zhy.utils.http.okhttp;
    
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Handler;
    import android.os.Looper;
    import android.widget.ImageView;
    
    import com.google.gson.Gson;
    import com.google.gson.internal.$Gson$Types;
    import com.squareup.okhttp.Call;
    import com.squareup.okhttp.Callback;
    import com.squareup.okhttp.FormEncodingBuilder;
    import com.squareup.okhttp.Headers;
    import com.squareup.okhttp.MediaType;
    import com.squareup.okhttp.MultipartBuilder;
    import com.squareup.okhttp.OkHttpClient;
    import com.squareup.okhttp.Request;
    import com.squareup.okhttp.RequestBody;
    import com.squareup.okhttp.Response;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.net.CookieManager;
    import java.net.CookiePolicy;
    import java.net.FileNameMap;
    import java.net.URLConnection;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * Created by zhy on 15/8/17.
     */
    public class OkHttpClientManager
    {
        private static OkHttpClientManager mInstance;
        private OkHttpClient mOkHttpClient;
        private Handler mDelivery;
        private Gson mGson;
    
    
        private static final String TAG = "OkHttpClientManager";
    
        private OkHttpClientManager()
        {
            mOkHttpClient = new OkHttpClient();
            //cookie enabled
            mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
            mDelivery = new Handler(Looper.getMainLooper());
            mGson = new Gson();
        }
    
        public static OkHttpClientManager getInstance()
        {
            if (mInstance == null)
            {
                synchronized (OkHttpClientManager.class)
                {
                    if (mInstance == null)
                    {
                        mInstance = new OkHttpClientManager();
                    }
                }
            }
            return mInstance;
        }
    
        /**
         * 同步的Get请求
         *
         * @param url
         * @return Response
         */
        private Response _getAsyn(String url) throws IOException
        {
            final Request request = new Request.Builder()
                    .url(url)
                    .build();
            Call call = mOkHttpClient.newCall(request);
            Response execute = call.execute();
            return execute;
        }
    
        /**
         * 同步的Get请求
         *
         * @param url
         * @return 字符串
         */
        private String _getAsString(String url) throws IOException
        {
            Response execute = _getAsyn(url);
            return execute.body().string();
        }
    
    
        /**
         * 异步的get请求
         *
         * @param url
         * @param callback
         */
        private void _getAsyn(String url, final ResultCallback callback)
        {
            final Request request = new Request.Builder()
                    .url(url)
                    .build();
            deliveryResult(callback, request);
        }
    
    
        /**
         * 同步的Post请求
         *
         * @param url
         * @param params post的参数
         * @return
         */
        private Response _post(String url, Param... params) throws IOException
        {
            Request request = buildPostRequest(url, params);
            Response response = mOkHttpClient.newCall(request).execute();
            return response;
        }
    
    
        /**
         * 同步的Post请求
         *
         * @param url
         * @param params post的参数
         * @return 字符串
         */
        private String _postAsString(String url, Param... params) throws IOException
        {
            Response response = _post(url, params);
            return response.body().string();
        }
    
        /**
         * 异步的post请求
         *
         * @param url
         * @param callback
         * @param params
         */
        private void _postAsyn(String url, final ResultCallback callback, Param... params)
        {
            Request request = buildPostRequest(url, params);
            deliveryResult(callback, request);
        }
    
        /**
         * 异步的post请求
         *
         * @param url
         * @param callback
         * @param params
         */
        private void _postAsyn(String url, final ResultCallback callback, Map<String, String> params)
        {
            Param[] paramsArr = map2Params(params);
            Request request = buildPostRequest(url, paramsArr);
            deliveryResult(callback, request);
        }
    
        /**
         * 同步基于post的文件上传
         *
         * @param params
         * @return
         */
        private Response _post(String url, File[] files, String[] fileKeys, Param... params) throws IOException
        {
            Request request = buildMultipartFormRequest(url, files, fileKeys, params);
            return mOkHttpClient.newCall(request).execute();
        }
    
        private Response _post(String url, File file, String fileKey) throws IOException
        {
            Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null);
            return mOkHttpClient.newCall(request).execute();
        }
    
        private Response _post(String url, File file, String fileKey, Param... params) throws IOException
        {
            Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, params);
            return mOkHttpClient.newCall(request).execute();
        }
    
        /**
         * 异步基于post的文件上传
         *
         * @param url
         * @param callback
         * @param files
         * @param fileKeys
         * @throws IOException
         */
        private void _postAsyn(String url, ResultCallback callback, File[] files, String[] fileKeys, Param... params) throws IOException
        {
            Request request = buildMultipartFormRequest(url, files, fileKeys, params);
            deliveryResult(callback, request);
        }
    
        /**
         * 异步基于post的文件上传,单文件不带参数上传
         *
         * @param url
         * @param callback
         * @param file
         * @param fileKey
         * @throws IOException
         */
        private void _postAsyn(String url, ResultCallback callback, File file, String fileKey) throws IOException
        {
            Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null);
            deliveryResult(callback, request);
        }
    
        /**
         * 异步基于post的文件上传,单文件且携带其他form参数上传
         *
         * @param url
         * @param callback
         * @param file
         * @param fileKey
         * @param params
         * @throws IOException
         */
        private void _postAsyn(String url, ResultCallback callback, File file, String fileKey, Param... params) throws IOException
        {
            Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, params);
            deliveryResult(callback, request);
        }
    
        /**
         * 异步下载文件
         *
         * @param url
         * @param destFileDir 本地文件存储的文件夹
         * @param callback
         */
        private void _downloadAsyn(final String url, final String destFileDir, final ResultCallback callback)
        {
            final Request request = new Request.Builder()
                    .url(url)
                    .build();
            final Call call = mOkHttpClient.newCall(request);
            call.enqueue(new Callback()
            {
                @Override
                public void onFailure(final Request request, final IOException e)
                {
                    sendFailedStringCallback(request, e, callback);
                }
    
                @Override
                public void onResponse(Response response)
                {
                    InputStream is = null;
                    byte[] buf = new byte[2048];
                    int len = 0;
                    FileOutputStream fos = null;
                    try
                    {
                        is = response.body().byteStream();
                        File file = new File(destFileDir, getFileName(url));
                        fos = new FileOutputStream(file);
                        while ((len = is.read(buf)) != -1)
                        {
                            fos.write(buf, 0, len);
                        }
                        fos.flush();
                        //如果下载文件成功,第一个参数为文件的绝对路径
                        sendSuccessResultCallback(file.getAbsolutePath(), callback);
                    } catch (IOException e)
                    {
                        sendFailedStringCallback(response.request(), e, callback);
                    } finally
                    {
                        try
                        {
                            if (is != null) is.close();
                        } catch (IOException e)
                        {
                        }
                        try
                        {
                            if (fos != null) fos.close();
                        } catch (IOException e)
                        {
                        }
                    }
    
                }
            });
        }
    
        private String getFileName(String path)
        {
            int separatorIndex = path.lastIndexOf("/");
            return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length());
        }
    
        /**
         * 加载图片
         *
         * @param view
         * @param url
         * @throws IOException
         */
        private void _displayImage(final ImageView view, final String url, final int errorResId)
        {
            final Request request = new Request.Builder()
                    .url(url)
                    .build();
            Call call = mOkHttpClient.newCall(request);
            call.enqueue(new Callback()
            {
                @Override
                public void onFailure(Request request, IOException e)
                {
                    setErrorResId(view, errorResId);
                }
    
                @Override
                public void onResponse(Response response)
                {
                    InputStream is = null;
                    try
                    {
                        is = response.body().byteStream();
                        ImageUtils.ImageSize actualImageSize = ImageUtils.getImageSize(is);
                        ImageUtils.ImageSize imageViewSize = ImageUtils.getImageViewSize(view);
                        int inSampleSize = ImageUtils.calculateInSampleSize(actualImageSize, imageViewSize);
                        try
                        {
                            is.reset();
                        } catch (IOException e)
                        {
                            response = _getAsyn(url);
                            is = response.body().byteStream();
                        }
    
                        BitmapFactory.Options ops = new BitmapFactory.Options();
                        ops.inJustDecodeBounds = false;
                        ops.inSampleSize = inSampleSize;
                        final Bitmap bm = BitmapFactory.decodeStream(is, null, ops);
                        mDelivery.post(new Runnable()
                        {
                            @Override
                            public void run()
                            {
                                view.setImageBitmap(bm);
                            }
                        });
                    } catch (Exception e)
                    {
                        setErrorResId(view, errorResId);
    
                    } finally
                    {
                        if (is != null) try
                        {
                            is.close();
                        } catch (IOException e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            });
    
    
        }
    
        private void setErrorResId(final ImageView view, final int errorResId)
        {
            mDelivery.post(new Runnable()
            {
                @Override
                public void run()
                {
                    view.setImageResource(errorResId);
                }
            });
        }
    
    
        //*************对外公布的方法************
    
    
        public static Response getAsyn(String url) throws IOException
        {
            return getInstance()._getAsyn(url);
        }
    
    
        public static String getAsString(String url) throws IOException
        {
            return getInstance()._getAsString(url);
        }
    
        public static void getAsyn(String url, ResultCallback callback)
        {
            getInstance()._getAsyn(url, callback);
        }
    
        public static Response post(String url, Param... params) throws IOException
        {
            return getInstance()._post(url, params);
        }
    
        public static String postAsString(String url, Param... params) throws IOException
        {
            return getInstance()._postAsString(url, params);
        }
    
        public static void postAsyn(String url, final ResultCallback callback, Param... params)
        {
            getInstance()._postAsyn(url, callback, params);
        }
    
    
        public static void postAsyn(String url, final ResultCallback callback, Map<String, String> params)
        {
            getInstance()._postAsyn(url, callback, params);
        }
    
    
        public static Response post(String url, File[] files, String[] fileKeys, Param... params) throws IOException
        {
            return getInstance()._post(url, files, fileKeys, params);
        }
    
        public static Response post(String url, File file, String fileKey) throws IOException
        {
            return getInstance()._post(url, file, fileKey);
        }
    
        public static Response post(String url, File file, String fileKey, Param... params) throws IOException
        {
            return getInstance()._post(url, file, fileKey, params);
        }
    
        public static void postAsyn(String url, ResultCallback callback, File[] files, String[] fileKeys, Param... params) throws IOException
        {
            getInstance()._postAsyn(url, callback, files, fileKeys, params);
        }
    
    
        public static void postAsyn(String url, ResultCallback callback, File file, String fileKey) throws IOException
        {
            getInstance()._postAsyn(url, callback, file, fileKey);
        }
    
    
        public static void postAsyn(String url, ResultCallback callback, File file, String fileKey, Param... params) throws IOException
        {
            getInstance()._postAsyn(url, callback, file, fileKey, params);
        }
    
        public static void displayImage(final ImageView view, String url, int errorResId) throws IOException
        {
            getInstance()._displayImage(view, url, errorResId);
        }
    
    
        public static void displayImage(final ImageView view, String url)
        {
            getInstance()._displayImage(view, url, -1);
        }
    
        public static void downloadAsyn(String url, String destDir, ResultCallback callback)
        {
            getInstance()._downloadAsyn(url, destDir, callback);
        }
    
        //****************************
    
    
        private Request buildMultipartFormRequest(String url, File[] files,
                                                  String[] fileKeys, Param[] params)
        {
            params = validateParam(params);
    
            MultipartBuilder builder = new MultipartBuilder()
                    .type(MultipartBuilder.FORM);
    
            for (Param param : params)
            {
                builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + param.key + "\""),
                        RequestBody.create(null, param.value));
            }
            if (files != null)
            {
                RequestBody fileBody = null;
                for (int i = 0; i < files.length; i++)
                {
                    File file = files[i];
                    String fileName = file.getName();
                    fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
                    //TODO 根据文件名设置contentType
                    builder.addPart(Headers.of("Content-Disposition",
                                    "form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
                            fileBody);
                }
            }
    
            RequestBody requestBody = builder.build();
            return new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();
        }
    
        private String guessMimeType(String path)
        {
            FileNameMap fileNameMap = URLConnection.getFileNameMap();
            String contentTypeFor = fileNameMap.getContentTypeFor(path);
            if (contentTypeFor == null)
            {
                contentTypeFor = "application/octet-stream";
            }
            return contentTypeFor;
        }
    
    
        private Param[] validateParam(Param[] params)
        {
            if (params == null)
                return new Param[0];
            else return params;
        }
    
        private Param[] map2Params(Map<String, String> params)
        {
            if (params == null) return new Param[0];
            int size = params.size();
            Param[] res = new Param[size];
            Set<Map.Entry<String, String>> entries = params.entrySet();
            int i = 0;
            for (Map.Entry<String, String> entry : entries)
            {
                res[i++] = new Param(entry.getKey(), entry.getValue());
            }
            return res;
        }
    
        private static final String SESSION_KEY = "Set-Cookie";
        private static final String mSessionKey = "JSESSIONID";
    
        private Map<String, String> mSessions = new HashMap<String, String>();
    
        private void deliveryResult(final ResultCallback callback, Request request)
        {
            mOkHttpClient.newCall(request).enqueue(new Callback()
            {
                @Override
                public void onFailure(final Request request, final IOException e)
                {
                    sendFailedStringCallback(request, e, callback);
                }
    
                @Override
                public void onResponse(final Response response)
                {
                    try
                    {
                        final String string = response.body().string();
                        if (callback.mType == String.class)
                        {
                            sendSuccessResultCallback(string, callback);
                        } else
                        {
                            Object o = mGson.fromJson(string, callback.mType);
                            sendSuccessResultCallback(o, callback);
                        }
    
    
                    } catch (IOException e)
                    {
                        sendFailedStringCallback(response.request(), e, callback);
                    } catch (com.google.gson.JsonParseException e)//Json解析的错误
                    {
                        sendFailedStringCallback(response.request(), e, callback);
                    }
    
                }
            });
        }
    
        private void sendFailedStringCallback(final Request request, final Exception e, final ResultCallback callback)
        {
            mDelivery.post(new Runnable()
            {
                @Override
                public void run()
                {
                    if (callback != null)
                        callback.onError(request, e);
                }
            });
        }
    
        private void sendSuccessResultCallback(final Object object, final ResultCallback callback)
        {
            mDelivery.post(new Runnable()
            {
                @Override
                public void run()
                {
                    if (callback != null)
                    {
                        callback.onResponse(object);
                    }
                }
            });
        }
    
        private Request buildPostRequest(String url, Param[] params)
        {
            if (params == null)
            {
                params = new Param[0];
            }
            FormEncodingBuilder builder = new FormEncodingBuilder();
            for (Param param : params)
            {
                builder.add(param.key, param.value);
            }
            RequestBody requestBody = builder.build();
            return new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();
        }
    
    
        public static abstract class ResultCallback<T>
        {
            Type mType;
    
            public ResultCallback()
            {
                mType = getSuperclassTypeParameter(getClass());
            }
    
            static Type getSuperclassTypeParameter(Class<?> subclass)
            {
                Type superclass = subclass.getGenericSuperclass();
                if (superclass instanceof Class)
                {
                    throw new RuntimeException("Missing type parameter.");
                }
                ParameterizedType parameterized = (ParameterizedType) superclass;
                return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
            }
    
            public abstract void onError(Request request, Exception e);
    
            public abstract void onResponse(T response);
        }
    
        public static class Param
        {
            public Param()
            {
            }
    
            public Param(String key, String value)
            {
                this.key = key;
                this.value = value;
            }
    
            String key;
            String value;
        }
    
    
    }
    
    

    源码地址okhttp-utils,大家可以自己下载查看。


    欢迎关注我的微博:
    http://weibo.com/u/3165018720


    群号:463081660,欢迎入群

    微信公众号:hongyangAndroid
    (欢迎关注,第一时间推送博文信息)
    1422600516_2905.jpg

    参考文章

    展开全文
  • 网络通信的功能已经成为移动手机开发中每个APP必须具备的一个最基本的功能,本课程主要分为三大部分,第一部分主要讲网络通信...使你快速掌握okhttp的使用和精髓,期间会讲解一些面试中的常见问题,助你面试一臂之力。
  • Okhttp的简单介绍和使用(一)

    万次阅读 多人点赞 2016-01-25 13:47:33
    通过本篇可以了解到: 1、okhttp是什么 2、okhttp的优点 3、okhttp的简单使用

    前言:

    通过本篇,可以了解一下几点:

    • Android中网络请求进化
    • okhttp是什么
    • okhttp的简单使用

    如果有兴趣,可以看下我的另一篇,okhttp的简单封装:

    网络请求发展:

    • HttpURLConnection—>Apache HTTP Client—>Volley—->okHttp

    OkHttp是什么:

    OkHttp是一个高效的HTTP库:

    • 1.支持 SPDY ,共享同一个Socket来处理同一个服务器的所有请求
    • 2.如果SPDY不可用,则通过连接池来减少请求延时
    • 3.无缝的支持GZIP来减少数据流量
    • 4.缓存响应数据来减少重复的网络请求

    优点:

    • OkHttp会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。
    • 使用 OkHttp 无需重写您程序中的网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的API。如果您用了 Apache HttpClient,则OkHttp也提供了一个对应的okhttp-apache 模块

    Okhttp的基本使用,从以下五方面讲解:

    • 1.Get请求(同步和异步)
    • 2.POST请求表单(key-value)
    • 3.POST请求提交(JSON/String/文件等)(这个有待研究)
    • 4.文件下载
    • 5.请求超时设置

    GET请求同步方法

           OkHttpClient client=new OkHttpClient();
           Request request = new Request.Builder().url(url) .build();
           Response response= client.newCall(request).execute();
           String message=response.body().string();

    GET请求异步方法

            OkHttpClient client=new OkHttpClient();
            Request request = new Request.Builder().url(url).build();
            client.newCall(request).enqueue(new Callback() {
                        @Override
                        public void onFailure(Request request, IOException e) {
                        }
                        @Override
                        public void onResponse(Response response) throws IOException {
                        }
             });
    

    POST请求提交

    在这里解释一下,我在用3.0的时候,去找FormEncodingBuilder(),这个方法,找不到了,就去了他的官网查看了信息,找到了一下一段解释:

    • We’ve replaced the opaque FormEncodingBuilder with the more powerful FormBody and FormBody.Builder combo. Similarly we’ve upgraded MultipartBuilder into MultipartBody, MultipartBody.Part, and MultipartBody.Builder.

    okhttp3.0之前:

          OkHttpClient client = new OkHttpClient();
          RequestBody forBody = new FormEncodingBuilder().add("username","tom").add("password", "1110").build();
                    Request request=new Request.Builder().url(url).post(forBody).build();
                    client.newCall(request).enqueue(new Callback() {
                        @Override
                        public void onFailure(Request request, IOException e) {
                        }
                        @Override
                        public void onResponse(Response response) throws IOException {
                            Log.d("xiaoming",response.body().string());
                        }
                    });   

    okhttp3.0之后

       OkHttpClient client = new OkHttpClient();
       FormBody formBody = new FormBody.Builder()
                    .add("type", "1")
                    .build();
      Request request=new Request.Builder().url(url).post(forBody).build();
                    client.newCall(request).enqueue(new Callback() {
                        @Override
                        public void onFailure(Request request, IOException e) {
                        }
                        @Override
                        public void onResponse(Response response) throws IOException {
                            Log.d("xiaoming",response.body().string());
                        }
                    });   

    文件下载

     String url = "http://www.0551fangchan.com/images/keupload/20120917171535_49309.jpg";
       //构建request对象 
            Request request = new Request.Builder().url(url).build();
            OkHttpClient client = new OkHttpClient();
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    InputStream inputStream = response.body().byteStream();
                    FileOutputStream fileOutputStream = new FileOutputStream(new File("/sdcard/logo.jpg"));
                    byte[] buffer = new byte[2048];
                    int len = 0;
                    while ((len = inputStream.read(buffer)) != -1) {
                        fileOutputStream.write(buffer, 0, len);
                    }
                    fileOutputStream.flush();
                    Log.d("wuyinlei", "文件下载成功...");
                }
            });

    超时设置:

    okhttp3.0之前:

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

    okhttp3.0之后:

            client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
            client.newBuilder().readTimeout(10,TimeUnit.SECONDS);
            client.newBuilder().writeTimeout(10,TimeUnit.SECONDS);

    下面看下结果演示:
    这里写图片描述

    注:不知道为什么,我的写入sdcard的权限也加了,就是提示我下载的时候没有权限,我只能用真机了,这里通过log日志来反馈下载成功:

    下面来看下代码,布局很简单,四个按钮,一个textview,这里就不解释了

    package com.example.okhttpdemo;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.concurrent.TimeUnit;
    
    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.FormBody;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        private Button syncGet;
        private Button asyncget;
        private Button post;
        private Button fileDownload,fengzhuang;
        private TextView tvtext;
        private String result;
    
    
    
    
        private static OkHttpClient client = new OkHttpClient();
    
    
        /**
         * 在这里直接设置连接超时,静态方法内,在构造方法被调用前就已经初始话了
         */
        static {
            client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
            client.newBuilder().readTimeout(10, TimeUnit.SECONDS);
            client.newBuilder().writeTimeout(10, TimeUnit.SECONDS);
        }
    
        private Request request;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initialize();
            initListener();
    
        }
    
        /**
         * 事件监听
         */
        private void initListener() {
            syncGet.setOnClickListener(this);
            asyncget.setOnClickListener(this);
            post.setOnClickListener(this);
            fileDownload.setOnClickListener(this);
            fengzhuang.setOnClickListener(this);
        }
    
    
        /**
         * 初始化布局控件
         */
        private void initialize() {
    
            syncGet = (Button) findViewById(R.id.syncGet);
            asyncget = (Button) findViewById(R.id.asyncget);
            post = (Button) findViewById(R.id.post);
            tvtext = (TextView) findViewById(R.id.tv_text);
            fileDownload = (Button) findViewById(R.id.fileDownload);
            fengzhuang = (Button) findViewById(R.id.fengzhuang);
        }
    
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.syncGet:
                    initSyncData();
                    break;
                case R.id.asyncget:
                    initAsyncGet();
                    break;
                case R.id.post:
                    initPost();
                    break;
                case R.id.fileDownload:
                    downLoadFile();
                    break;
                case R.id.fengzhuang:
                    break;
            }
        }
    
    
    
        /**
         * get请求同步方法
         */
        private void initSyncData() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        request = new Request.Builder().url(Contants.SYNC_URL).build();
                        Response response = client.newCall(request).execute();
                        result = response.body().string();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                tvtext.setText(result);
                                Log.d("MainActivity", "hello");
                            }
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
        }
    
        /**
         * 异步请求
         */
        private void initAsyncGet() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    request = new Request.Builder().url(Contants.ASYNC_URL).build();
                    client.newCall(request).enqueue(new Callback() {
    
                        /**
                         * A call is a request that has been prepared for execution. A call can be canceled. As this object
                         * represents a single request/response pair (stream), it cannot be executed twice.
                         *
                         *
                         * @param call   是一个接口,  是一个准备好的可以执行的request
                         *               可以取消,对位一个请求对象,只能单个请求
                         * @param e
                         */
                        @Override
                        public void onFailure(Call call, IOException e) {
                            Log.d("MainActivity", "请求失败");
                        }
    
                        /**
                         *
                         * @param call
                         * @param response   是一个响应请求
                         * @throws IOException
                         */
                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
                            /**
                             * 通过拿到response这个响应请求,然后通过body().string(),拿到请求到的数据
                             * 这里最好用string()  而不要用toString()
                             * toString()每个类都有的,是把对象转换为字符串
                             * string()是把流转为字符串
                             */
                            result = response.body().string();
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    tvtext.setText(result);
                                }
                            });
                        }
                    });
                }
            }).start();
        }
    
        /**
         * 表单提交
         */
        private void initPost() {
    
            String url = "http://112.124.22.238:8081/course_api/banner/query";
    
    
            FormBody formBody = new FormBody.Builder()
                    .add("type", "1")
                    .build();
            request = new Request.Builder().url(url)
                    .post(formBody).build();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    client.newCall(request).enqueue(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {
    
                        }
    
                        @Override
                        public void onResponse(Call call, final Response response) throws IOException {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    tvtext.setText("提交成功");
                                }
                            });
                        }
                    });
                }
            }).start();
    
        }
    
        /**
         * 文件下载地址
         */
        private void downLoadFile() {
            String url = "http://www.0551fangchan.com/images/keupload/20120917171535_49309.jpg";
            request = new Request.Builder().url(url).build();
            OkHttpClient client = new OkHttpClient();
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
    
                    //把请求成功的response转为字节流
                    InputStream inputStream = response.body().byteStream();
    
                    /**
                     * 在这里要加上权限   在mainfests文件中
                     * <uses-permission android:name="android.permission.INTERNET"/>
                     * <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
                     */
    
                    //在这里用到了文件输出流
                    FileOutputStream fileOutputStream = new FileOutputStream(new File("/sdcard/logo.jpg"));
                   //定义一个字节数组
                    byte[] buffer = new byte[2048];
                    int len = 0;
                    while ((len = inputStream.read(buffer)) != -1) {
                        //写出到文件
                        fileOutputStream.write(buffer, 0, len);
                    }
                    //关闭输出流
                    fileOutputStream.flush();
                    Log.d("wuyinlei", "文件下载成功...");
                }
            });
        }
    
    
    }
    
    

    好了,简单的okhttp使用就介绍到这里了,接下来会对其完成以下简单的封装。

    由于okhttp3.0较于之前的有些变化,大家使用的时候可以去看下他们官方的说明,这样在使用中就会少了不必要的麻烦了。

    展开全文
  • OkHttp官方教程解析-彻底入门OkHttp使用

    万次阅读 多人点赞 2018-03-29 09:54:29
    最近半年来身边开发的朋友越来越多的提到OkHttp,上谷歌百度一下,确实OkHttp成了时下最火的HTTP框架,于是我也开始放下Volley,转而关注OkHttp,五一期间仔细看了官方WiKi介绍(我喜欢学习官方的文档),现在把自己...
    版权声明:本文为博主原创文章,未经博主允许不得转载;来自http://blog.csdn.net/mynameishuangshuai https://blog.csdn.net/mynameishuangshuai/article/details/51303446

           最近半年来身边开发的朋友越来越多的提到OkHttp,上谷歌百度一下,确实OkHttp成了时下最火的HTTP框架,于是我也开始放下Volley,转而关注OkHttp,五一期间仔细看了官方WiKi介绍(我喜欢学习官方的文档),现在把自己整理的官方教程分享给大家,希望给初学者带来帮助。
           OkHttp官网地址:http://square.github.io/okhttp/
           OkHttp GitHub地址:https://github.com/square/okhttp
    官网的自我介绍:
           HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP efficiently makes your stuff load faster and saves bandwidth.
    OkHttp is an HTTP client that’s efficient by default:

    •   HTTP/2 support allows all requests to the same host to share a socket.
    •   Connection pooling reduces request latency (if HTTP/2 isn’t available).
    •   Transparent GZIP shrinks download sizes.
    •   Response caching avoids the network completely for repeat requests.
    • 1
    • 2
    • 3
    • 4

           OkHttp perseveres when the network is troublesome: it will silently recover from common connection problems. If your service has multiple IP addresses OkHttp will attempt alternate addresses if the first connect fails. This is necessary for IPv4+IPv6 and for services hosted in redundant data centers. OkHttp initiates new connections with modern TLS features (SNI, ALPN), and falls back to TLS 1.0 if the handshake fails.
           Using OkHttp is easy. Its request/response API is designed with fluent builders and immutability. It supports both synchronous blocking calls and async calls with callbacks.
           OkHttp supports Android 2.3 and above. For Java, the minimum requirement is 1.7.
           概括起来说OkHttp是一款优秀的HTTP框架,它支持get请求和post请求,支持基于Http的文件上传和下载,支持加载图片,支持下载文件透明的GZIP压缩,支持响应缓存避免重复的网络请求,支持使用连接池来降低响应延迟问题。

    配置方法

    (一)导入Jar包
    点击下面链接下载最新v3.2.0 JAR
    http://repo1.maven.org/maven2/com/squareup/okhttp3/okhttp/3.2.0/okhttp-3.2.0.jar
    (二)通过构建方式导入
    MAVEN

    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>3.2.0</version>
    </dependency>
    • 1
    • 2
    • 3
    • 4
    • 5

    GRADLE

    compile 'com.squareup.okhttp3:okhttp:3.2.0'
    • 1

    基本要求

    Requests(请求)

           每一个HTTP请求中都应该包含一个URL,一个GET或POST方法以及Header或其他参数,当然还可以含特定内容类型的数据流。

    Responses(响应)

           响应则包含一个回复代码(200代表成功,404代表未找到),Header和定制可选的body。

    基本使用

           在日常开发中最常用到的网络请求就是GET和POST两种请求方式。

    HTTP GET

    OkHttpClient client = new OkHttpClient();
    String run(String url) throws IOException {
        Request request = new Request.Builder().url(url).build();
        Response response = client.newCall(request).execute();
        if (response.isSuccessful()) {
            return response.body().string();
        } else {
            throw new IOException("Unexpected code " + response);
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Request是OkHttp中访问的请求,Builder是辅助类,Response即OkHttp中的响应。
    Response类:

    public boolean isSuccessful()
    Returns true if the code is in [200..300), which means the request was successfully received, understood, and accepted.
    response.body()返回ResponseBody类
    • 1
    • 2
    • 3

    可以方便的获取string

    public final String string() throws IOException
    Returns the response as a string decoded with the charset of the Content-Type header. If that header is either absent or lacks a charset, this will attempt to decode the response body as UTF-8.
    Throws:
    IOException
    • 1
    • 2
    • 3
    • 4

    当然也能获取到流的形式:
    public final InputStream byteStream()

    HTTP POST

    POST提交Json数据

    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    OkHttpClient client = new OkHttpClient();
    String post(String url, String json) throws IOException {
        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
          .url(url)
          .post(body)
          .build();
        Response response = client.newCall(request).execute();
        f (response.isSuccessful()) {
            return response.body().string();
        } else {
            throw new IOException("Unexpected code " + response);
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用Request的post方法来提交请求体RequestBody
    POST提交键值对
    OkHttp也可以通过POST方式把键值对数据传送到服务器

    OkHttpClient client = new OkHttpClient();
    String post(String url, String json) throws IOException {
        RequestBody formBody = new FormEncodingBuilder()
        .add("platform", "android")
        .add("name", "bug")
        .add("subject", "XXXXXXXXXXXXXXX")
        .build();
    
        Request request = new Request.Builder()
          .url(url)
          .post(body)
          .build();
    
        Response response = client.newCall(request).execute();
        if (response.isSuccessful()) {
            return response.body().string();
        } else {
            throw new IOException("Unexpected code " + response);
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    案例

    布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:orientation="horizontal">
    
            <Button
                android:id="@+id/bt_get"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="乌云Get请求"/>
    
            <Button
                android:id="@+id/bt_post"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="乌云Post请求"/>
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/tv_show"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </LinearLayout>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    这里写图片描述
    Java代码:
    由于android本身是不允许在UI线程做网络请求操作的,所以我们自己写个线程完成网络操作

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    import com.squareup.okhttp.FormEncodingBuilder;
    import com.squareup.okhttp.OkHttpClient;
    import com.squareup.okhttp.Request;
    import com.squareup.okhttp.RequestBody;
    import com.squareup.okhttp.Response;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        private Button bt_get;
        private Button bt_post;
    
        final OkHttpClient client = new OkHttpClient();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main2);
    
            bt_get=(Button)findViewById(R.id.bt_get);
            bt_post=(Button)findViewById(R.id.bt_post);
    
            bt_get.setOnClickListener(this);
            bt_post.setOnClickListener(this);
    
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()){
                case R.id.bt_get:
                    getRequest();
                    break;
    
                case R.id.bt_post:
                    postRequest();
                    break;
    
            }
        }
    
        private void getRequest() {
    
            final Request request=new Request.Builder()
                    .get()
                    .tag(this)
                    .url("http://www.wooyun.org")
                    .build();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Response response = null;
                    try {
                        response = client.newCall(request).execute();
                        if (response.isSuccessful()) {
                            Log.i("WY","打印GET响应的数据:" + response.body().string());
                        } else {
                            throw new IOException("Unexpected code " + response);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
        }
    
        private void postRequest() {
    
            RequestBody formBody = new FormEncodingBuilder()
                    .add("","")
                    .build();
    
            final Request request = new Request.Builder()
                    .url("http://www.wooyun.org")
                    .post(formBody)
                    .build();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Response response = null;
                    try {
                        response = client.newCall(request).execute();
                        if (response.isSuccessful()) {
                            Log.i("WY","打印POST响应的数据:" + response.body().string());
                        } else {
                            throw new IOException("Unexpected code " + response);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
        }
    
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

    执行结果:
    这里写图片描述

    官方Recipes

    Synchronous Get(同步Get)

    下载一个文件,打印他的响应头,以string形式打印响应体。
           响应体的 string() 方法对于小文档来说十分方便、高效。但是如果响应体太大(超过1MB),应避免适应 string()方法 ,因为他会将把整个文档加载到内存中。对于超过1MB的响应body,应使用流的方式来处理body。

    private final OkHttpClient client = new OkHttpClient();
    
      public void run() throws Exception {
        Request request = new Request.Builder()
            .url("http://publicobject.com/helloworld.txt")
            .build();
    
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
    
        Headers responseHeaders = response.headers();
        for (int i = 0; i < responseHeaders.size(); i++) {
          System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
        }
    
        System.out.println(response.body().string());
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Asynchronous Get(异步Get)

           在一个工作线程中下载文件,当响应可读时回调Callback接口。读取响应时会阻塞当前线程。OkHttp现阶段不提供异步api来接收响应体。

    private final OkHttpClient client = new OkHttpClient();
    
      public void run() throws Exception {
        Request request = new Request.Builder()
            .url("http://publicobject.com/helloworld.txt")
            .build();
    
        client.newCall(request).enqueue(new Callback() {
          @Override public void onFailure(Call call, IOException e) {
            e.printStackTrace();
          }
    
          @Override public void onResponse(Call call, Response response) throws IOException {
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
    
            Headers responseHeaders = response.headers();
            for (int i = 0, size = responseHeaders.size(); i < size; i++) {
              System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
            }
    
            System.out.println(response.body().string());
          }
        });
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    Accessing Headers(提取响应头)

    典型的HTTP头 像是一个 Map

    private final OkHttpClient client = new OkHttpClient();
    
      public void run() 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"));
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Posting a String(Post方式提交String)

           使用HTTP POST提交请求到服务。这个例子提交了一个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());
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    Post Streaming(Post方式提交流)

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

    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 {
        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);
          }
        };
    
        Request request = new Request.Builder()
            .url("https://api.github.com/markdown/raw")
            .post(requestBody)
            .build();
    
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
    
        System.out.println(response.body().string());
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    Posting a File(Post方式提交文件)

    以文件作为请求体是十分简单的。

    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 {
        File file = new File("README.md");
    
        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());
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Posting form parameters(Post方式提交表单)

           使用FormEncodingBuilder来构建和HTML标签相同效果的请求体。键值对将使用一种HTML兼容形式的URL编码来进行编码。

    private final OkHttpClient client = new OkHttpClient();
    
      public void run() throws Exception {
        RequestBody formBody = new FormBody.Builder()
            .add("search", "Jurassic Park")
            .build();
        Request request = new Request.Builder()
            .url("https://en.wikipedia.org/w/index.php")
            .post(formBody)
            .build();
    
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
    
        System.out.println(response.body().string());
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Posting a multipart request(Post方式提交分块请求)

           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 run() throws Exception {
        // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
        RequestBody requestBody = new MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart("title", "Square Logo")
            .addFormDataPart("image", "logo-square.png",
                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());
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    Parse a JSON Response With Gson(使用GSON解析JSON响应)

           Gson是一个在JSON和Java对象之间转换非常方便的api。这里我们用Gson来解析Github API的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);
        for (Map.Entry<String, GistFile> entry : gist.files.entrySet()) {
          System.out.println(entry.getKey());
          System.out.println(entry.getValue().content);
        }
      }
    
      static class Gist {
        Map<String, GistFile> files;
      }
    
      static class GistFile {
        String content;
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    Response Caching(响应缓存)

           为了缓存响应,你需要一个你可以读写的缓存目录,和缓存大小的限制。这个缓存目录应该是私有的,不信任的程序应不能读取缓存内容。
           一个缓存目录同时拥有多个缓存访问是错误的。大多数程序只需要调用一次new OkHttp(),在第一次调用时配置好缓存,然后其他地方只需要调用这个实例就可以了。否则两个缓存示例互相干扰,破坏响应缓存,而且有可能会导致程序崩溃。
           响应缓存使用HTTP头作为配置。你可以在请求头中添加Cache-Control: max-stale=3600 ,OkHttp缓存会支持。你的服务通过响应头确定响应缓存多长时间,例如使用Cache-Control: max-age=9600。

    private final OkHttpClient client;
    
      public CacheResponse(File cacheDirectory) throws Exception {
        int cacheSize = 10 * 1024 * 1024; // 10 MiB
        Cache cache = new Cache(cacheDirectory, cacheSize);
    
        client = new OkHttpClient.Builder()
            .cache(cache)
            .build();
      }
    
      public void run() throws Exception {
        Request request = new Request.Builder()
            .url("http://publicobject.com/helloworld.txt")
            .build();
    
        Response response1 = client.newCall(request).execute();
        if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1);
    
        String response1Body = response1.body().string();
        System.out.println("Response 1 response:          " + response1);
        System.out.println("Response 1 cache response:    " + response1.cacheResponse());
        System.out.println("Response 1 network response:  " + response1.networkResponse());
    
        Response response2 = client.newCall(request).execute();
        if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2);
    
        String response2Body = response2.body().string();
        System.out.println("Response 2 response:          " + response2);
        System.out.println("Response 2 cache response:    " + response2.cacheResponse());
        System.out.println("Response 2 network response:  " + response2.networkResponse());
    
        System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body));
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

           为了防止使用缓存的响应,可以用CacheControl.FORCE_NETWORK。为了防止它使用网络,使用CacheControl.FORCE_CACHE。需要注意的是:如果您使用FORCE_CACHE和网络的响应需求,OkHttp则会返回一个504提示,告诉你不可满足请求响应。
           Canceling a Call(取消一个Call)
           使用Call.cancel()可以立即停止掉一个正在执行的call。如果一个线程正在写请求或者读响应,将会引发IOException。当call没有必要的时候,使用这个api可以节约网络资源。例如当用户离开一个应用时。不管同步还是异步的call都可以取消。
           你可以通过tags来同时取消多个请求。当你构建一请求时,使用RequestBuilder.tag(tag)来分配一个标签。之后你就可以用OkHttpClient.cancel(tag)来取消所有带有这个tag的call。.

     private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
      private final OkHttpClient client = new OkHttpClient();
    
      public void run() throws Exception {
        Request request = new Request.Builder()
            .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
            .build();
    
        final long startNanos = System.nanoTime();
        final Call call = client.newCall(request);
    
        // Schedule a job to cancel the call in 1 second.
        executor.schedule(new Runnable() {
          @Override public void run() {
            System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startNanos) / 1e9f);
            call.cancel();
            System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startNanos) / 1e9f);
          }
        }, 1, TimeUnit.SECONDS);
    
        try {
          System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f);
          Response response = call.execute();
          System.out.printf("%.2f Call was expected to fail, but completed: %s%n",
              (System.nanoTime() - startNanos) / 1e9f, response);
        } catch (IOException e) {
          System.out.printf("%.2f Call failed as expected: %s%n",
              (System.nanoTime() - startNanos) / 1e9f, e);
        }
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    Timeouts(超时)

           没有响应时使用超时结束call。没有响应的原因可能是客户点链接问题、服务器可用性问题或者这之间的其他东西。OkHttp支持连接,读取和写入超时。

    private final OkHttpClient client;
    
      public ConfigureTimeouts() throws Exception {
        client = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build();
      }
    
      public void run() throws Exception {
        Request request = new Request.Builder()
            .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
            .build();
    
        Response response = client.newCall(request).execute();
        System.out.println("Response completed: " + response);
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Per-call Configuration(每个Call的配置)

           使用OkHttpClient,所有的HTTP Client配置包括代理设置、超时设置、缓存设置。当你需要为单个call改变配置的时候,clone 一个 OkHttpClient。这个api将会返回一个浅拷贝(shallow copy),你可以用来单独自定义。下面的例子中,我们让一个请求是500ms的超时、另一个是3000ms的超时。

    private final OkHttpClient client = new OkHttpClient();
    
      public void run() throws Exception {
        Request request = new Request.Builder()
            .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay.
            .build();
    
        try {
          // Copy to customize OkHttp for this request.
          OkHttpClient copy = client.newBuilder()
              .readTimeout(500, TimeUnit.MILLISECONDS)
              .build();
    
          Response response = copy.newCall(request).execute();
          System.out.println("Response 1 succeeded: " + response);
        } catch (IOException e) {
          System.out.println("Response 1 failed: " + e);
        }
    
        try {
          // Copy to customize OkHttp for this request.
          OkHttpClient copy = client.newBuilder()
              .readTimeout(3000, TimeUnit.MILLISECONDS)
              .build();
    
          Response response = copy.newCall(request).execute();
          System.out.println("Response 2 succeeded: " + response);
        } catch (IOException e) {
          System.out.println("Response 2 failed: " + e);
        }
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    Handling authentication(处理验证)

           OkHttp会自动重试未验证的请求。当响应是401 Not Authorized时,Authenticator会被要求提供证书。Authenticator的实现中需要建立一个新的包含证书的请求。如果没有证书可用,返回null来跳过尝试。

     private final OkHttpClient client;
    
      public Authenticate() {
        client = new OkHttpClient.Builder()
            .authenticator(new Authenticator() {
              @Override public Request authenticate(Route route, Response response) throws IOException {
                System.out.println("Authenticating for response: " + response);
                System.out.println("Challenges: " + response.challenges());
                String credential = Credentials.basic("jesse", "password1");
                return response.request().newBuilder()
                    .header("Authorization", credential)
                    .build();
              }
            })
            .build();
      }
    
      public void run() throws Exception {
        Request request = new Request.Builder()
            .url("http://publicobject.com/secrets/hellosecret.txt")
            .build();
    
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
    
        System.out.println(response.body().string());
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    To avoid making many retries when authentication isn’t working, you can return null to give up. For example, you may want to skip the retry when these exact credentials have already been attempted:

    if (credential.equals(response.request().header("Authorization"))) {
        return null; // If we already failed with these credentials, don't retry.
       }
    You may also skip the retry when you’ve hit an application-defined attempt limit:
      if (responseCount(response) >= 3) {
        return null; // If we've failed 3 times, give up.
      }
    This above code relies on this responseCount() method:
      private int responseCount(Response response) {
        int result = 1;
        while ((response = response.priorResponse()) != null) {
          result++;
        }
        return result;
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    OkHttp官方文档:https://github.com/square/okhttp/wiki
    参考链接:http://www.cnblogs.com/ct2011/p/3997368.html

    下一篇文章,我将会从具体开发的角度,封装一个高效的OkHttp框架分享给大家。

    安卓开发高级技术交流QQ群:108721298 欢迎入群

    微信公众号:mobilesafehome

    (本公众号支持投票)

    Android安全技术大本营

    转自:https://blog.csdn.net/mynameishuangshuai/article/details/51303446

    展开全文
  • 深入解析OkHttp3

    千次阅读 2018-06-15 17:08:16
    OkHttp是一个精巧的网络请求库,有如下特性: 1)支持http2,对一台机器的所有请求共享同一个socket 2)内置连接池,支持连接复用,减少延迟 3)支持透明的gzip压缩响应体 4)通过缓存避免重复的请求 5)请求失败时自动重...
  • OkHttp:基本使用详解

    万次阅读 2019-08-28 22:52:34
    简介 OkHttp是一个高效的HTTP客户端,它有以下默认特性...当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置...
  • OKHttp使用详解

    万次阅读 多人点赞 2017-04-29 12:38:55
    一,OKHttp介绍okhttp是一个第三方类库,用于android中请求网络。这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso和LeakCanary) 。用于替代HttpUrlConnection和Apache...
  • 基本使用——OkHttp3详细使用教程

    万次阅读 多人点赞 2017-08-30 15:36:35
    OkHttp现在应该算是最火的Http第三方库,Retrofit底层也是使用OkHttp,网上很多教程都写的不错,但是有些我认为重要的知识,大多一笔带过,所以我决定写一篇入门文章 OkHttp官网地址:...
  • Android网络编程(六)OkHttp3用法全解析

    万次阅读 多人点赞 2016-04-21 12:26:19
    上一篇介绍了OkHttp2.x的用法,这一篇文章我们来对照OkHttp2.x版本来看看,OkHttp3使用起来有那些变化。当然,看这篇文章前建议看一下前一篇文章Android网络编程(五)OkHttp2.x用法全解析。
  • okhttp3使用

    万次阅读 多人点赞 2016-06-03 11:02:12
    一、引入包在项目module下的build.gradle添加okhttp3依赖compile 'com.squareup.okhttp3:okhttp:3.3.1'二、基本使用1、okhttp3 Get 方法1.1 、okhttp3 同步 Get方法/** * 同步Get方法 */ private void okHttp_...
  • Android OkHttp3简介和使用详解

    万次阅读 2018-04-02 09:25:22
    OKHttp简介 OKHttp是一个处理网络请求的开源项目,Android 当前最火热网络框架,由移动支付Square公司贡献,用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient)。...
  • OkHttp3开发

    千次阅读 2018-01-05 10:19:03
    OkHttp3开发三部曲: 1、创建OkHttpClient,添加配置 2、创建请求 3、执行请求 下面分别来说说这三个步骤: 一、创建OkHttpClient 一个最简单的OkHttpClient [java] view plain copy ...
  • 基于OkHttp3封装网络请求框架

    万次阅读 2017-12-14 09:49:37
    网络请求可以说是开发一款移动APP最核心的基础功能了,通过实际工作中以及浏览了许多网络框架之后,本篇在这里分享慕课一位老师基于OkHttp封装的一个轻量的网络框架,至于为什么说它轻量,因为代码少啊!在这里会...
  • Okhttp3使用

    万次阅读 2018-03-28 11:05:16
    历史发展 Okhttp是一个处理网络请求的开源项目,是安卓最火热的轻量级框架,Retrofit底层也是使用Okhttp,接下来长话短说,... compile 'com.squareup.okhttp3:okhttp:3.9.0' //2、json数据解析的工具 compile 'c...
  • okhttp3的基本使用

    万次阅读 多人点赞 2016-07-02 12:16:35
    okhttp3的基本使用
  • okhttp3 jar包

    2020-08-17 09:19:05
    当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接
  • OkHttp3网络协议的使用

    千次阅读 2017-03-21 17:39:21
    OkHttp3网络协议的使用 一、引入包 在项目module下的build.gradle添加okhttp3依赖 compile 'com.squareup.okhttp3:okhttp:3.3.1' 二、基本使用 1、okhttp3 Get 方法 1.1 、okhttp3 同步 Get方法 /** *...
  • OkHttp3

    2018-01-23 16:23:39
    1,compile 'com.squareup.okhttp3:okhttp:3.9.1'2,get OkHttpClient client = new OkHttpClient(); //创建一个Request Request request = new Request.Builder() .get()
  • okhttp3.Request request = new okhttp3.Request.Builder().url(url).post(formBody).build(); okhttp3.Response response = client.newCall(request).execute(); } </code></pre> <p>This is my php code:</p> ...

空空如也

1 2 3 4 5 ... 20
收藏数 58,533
精华内容 23,413
关键字:

okhttp