zoukankan      html  css  js  c++  java
  • Android 开发 框架系列 OkHttp使用详解

    简介

    okhttp是一个第三方类库,用于android中请求网络。这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso和LeakCanary) 。用于替代HttpUrlConnection和Apache HttpClient(android API23 里已移除HttpClient)。

    依赖

    implementation 'com.squareup.okhttp3:okhttp:4.4.0'

    同步请求方式(get请求)

    步骤一  创建请求接口网址

    我使用了http://www.sosoapi.com/ 来创建了一个访问接口,用来验证OkHttp是否请求成功。如果你有兴趣了解,可以直接进入网站,里面有详细的demo演示。后续我将不在赘述这段。

    我在请求响应里添加了一段JSON数据:

    [
        {
            "name": "get测试",
            "content": "你成功获取了数据"
        }
    ]

    步骤二  创建JSON解析方法

    这里我写一下解析JSON数据的方法,来解析get或者post得到的JSON数据。后续我将不在赘述这段。

    /**
         * JSON 解析方法
         * @param jsonData
         * @return
         */
        public String readJSONContent(String jsonData){
            try {
                StringBuffer sb = new StringBuffer();
                JSONArray jsonArray = new JSONArray(jsonData);
                for (int i=0;i<jsonArray.length();i++){
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    sb.append(jsonObject.getString("name")+"
    ");
                    sb.append(jsonObject.getString("content")+"
    ");
                }
                return sb.toString();
            } catch (JSONException e) {
                Log.e("JSONException错误", "readContent: "+e.toString());
                return e.toString();
            }
        }

    步骤三  创建OkHttp 同步请求

    /**
         * 同步请求
         */
        public void synchro(){
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    OkHttpClient okHttpClient = new OkHttpClient();//创建单例
                    Request request = new Request.Builder()//创建请求
                            .url("http://www.sosoapi.com/pass/mock/12003/test/gettest")
                            .build();
                    try {
                        Response response = okHttpClient.newCall(request).execute();//执行请求
                        mContent = response.body().string();//得到返回响应,注意response.body().string() 只能调用一次!
    
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mtextView.setText(readJSONContent(mContent));
                            }
                        });
                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.e("OkHttpActivity", e.toString() );
                    }
                }
            });
            thread.start();
        }

    注意!response.body().string() 只能调用一次! 因为响应主体 RessponseBody 持有的资源可能会很大,所以 OkHttp 并不会将其直接保存到内存中,只是持有数据流连接。只有当我们需要时,才会从服务器获取数据并返回。同时,考虑到应用重复读取数据的可能性很小,所以将其设计为一次性流(one-shot),读取后即 '关闭并释放资源'

    效果图:

     

    异步请求方式(get请求)

    注意1:异步请求方式,请求的回调会在子线程里,所以如果需要更新UI你需要切换到主线程。且你不需要在new 一个线程包裹这个异步请求了。另外如何切换到主线程请使用 Handler 例子:

    注意2:在异步请求方法里,请不要将 public void onResponse(Call call, final Response response)回调里的response回调数据放到UI线程里解析,因为有一个天坑,有可能在UI线程里解析的时候response里面却还没有塞入数据(我也觉得很神奇,不知道写okhttp的公司是怎么想的,为什么不处理完所有数据在提供回调)

    private Handler mHandler = new Handler(Looper.getMainLooper());
                mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            //主线程
    
                        }
                    });    

    创建异步请求

         /**
         * get异步请求
         */
          public void asynchronous(){
              OkHttpClient okHttpClient = new OkHttpClient();
              Request request = new Request.Builder()
                      .url("http://www.sosoapi.com/pass/mock/12003/test/gettest")
                      .build();
              okHttpClient.newCall(request).enqueue(new Callback() {
                  @Override
                  public void onFailure(Call call, IOException e) {
                      //失败回调
    
                  }
    
                  @Override
                  public void onResponse(Call call, final Response response) throws IOException {
                mContent = readJSONContent(response.body().string());//注意response.body().string() 只能调用一次!
    //响应成功,这个回调在子线程中,所以不需要创建线程 if (response.isSuccessful()){ //isSuccessful方法:如果代码位于(200…300)中,则返回true,这意味着请求已成功接收 runOnUiThread(new Runnable() { @Override public void run() { try { //因为在子线程,所以我们需要回到主线程中更新UI数据 mtextView.setText(mContent); } catch (IOException e) { e.printStackTrace(); } } }); } } }); }

    Post请求

    post请求也同时有同步与异步方法,与上面一致,所以这里就不展示了,下面我们来看看post请求发送

    /**
         * post请求
         */
        public void post(){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //实例
                    OkHttpClient okHttpClient = new OkHttpClient();
    
                    //创建post请求数据表单
                    RequestBody requestBody = new FormBody.Builder()
                            .add("name","请求post")
                            .add("password","123456")
                            .build();
                    //创建请求
                    final Request request = new Request.Builder()
                            .url("http://www.sosoapi.com/pass/mock/12003/test/posttest")
                            .post(requestBody)//添加post请求
                            .build();
    
                    try {
                        //发送请求得到响应
                        final Response response = okHttpClient.newCall(request).execute();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    mtextView.setText(readJSONContent(response.body().string()));//注意response.body().string() 只能调用一次!
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                }
            }).start();
    
        }

    效果图:

    取消网络请求

    取消okhttp的网络请求很简单只需要

    call.cancel();

    如何鉴别是网络异常还是主动取消,请求取消的回调在onFailure(Call call, IOException e)里回调,这个时候我们需要再次判断onFailure里回调的是我们自己主动取消的还是网络异常报错的

    mCall.enqueue(new Callback() {//发送请求
        @Override
        public void onFailure(final Call call, final IOException e) {
            if (call.isCanceled()){
                listener.onCancel();
    
            }else {
                listener.onFailure(call, e);
            }
        }     
    //省略下面代码...

    RequestBody创建

    RequestBody是okhttp  post发送数据配置类.在这之前我们先了解下回顾一下body类型

    http有四种body类型,Content-Type POST提交数据的方式:
    • application/x-www-form-urlencoded 表单数据
    • multipart/form-data 表单文件上传
    • application/json 序列化JSON数据
    • text/xml XML数据

    这些body类型需要在http header头部就写上,但是okhttp不需要我们手动在header写上类型了.okhttp提供了FormBody和MultipartBody的类型,方便你的快速创建application/x-www-form-urlencoded 与 multipart/form-data

    FormBody 创建方式

    /**
         * 此body是 默认application/x-www-form-urlencoded,你可以进入FormBody类查看,第一行静态常量就是这个
         */
       public void FormBody(){
           FormBody.Builder builder = new FormBody.Builder();
           builder.add("key","content");
           builder.build();
       }

    MultipartBody 创建方式

    /**
         * multipart/form-data
         */
       public void MultipartBody(){
           RequestBody requestBody = new RequestBody() {
               @Override
               public MediaType contentType() {
                   return null;
               }
    
               @Override
               public void writeTo(BufferedSink sink) throws IOException {
                   //上传流 sink.write()
    
    
               }
           };
           MultipartBody.Builder builder = new MultipartBody.Builder();
           builder.addFormDataPart("key","content");//表单数据
           builder.addFormDataPart("file_key","/path/image.jpg",requestBody);//文件数据
           MultipartBody multipartBody = builder.build();
       }

    手动创建4种body

    当然,有特殊需求你还可以添加手动其他body类型,create也支持好几种数据的上传形式

     /**
         * 手动创建4种body
         */
       public void RequestBody(){
           RequestBody applicationFormUrlencodedBody = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded; charset=utf-8"),new String("demo").getBytes());
           RequestBody multipartBody = RequestBody.create(MediaType.parse("multipart/form-data; charset=utf-8"),new File("/path/image.jpg"));
           RequestBody jsonBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),"content");
           RequestBody textbody = RequestBody.create(MediaType.parse("text/xml; charset=utf-8"),"content");
    
       }

     实现OkHttpClient客户端单例模式

    public class OkHttpClientCreate {
        private static final boolean IS_RETRY = false;//失败是否重连
        private static final int CONNECT_TIME = 10;//设置连接超时时间 单位:秒
        private static final int READ_TIME = 10;//设置读取超时时间
        private static final int WRITE_TIME = 10;//设置写入超时间
        private static OkHttpClient mOkHttpClient;
        public static OkHttpClient CreateClient(){
            if (mOkHttpClient == null){
                return mOkHttpClient = new OkHttpClient.Builder()
                        .retryOnConnectionFailure(IS_RETRY)
                        .connectTimeout(CONNECT_TIME,TimeUnit.SECONDS)//连接超时
                        .readTimeout(READ_TIME,TimeUnit.SECONDS)//读取超时
                        .writeTimeout(WRITE_TIME,TimeUnit.SECONDS)//写入超时
    //                    .callTimeout()//呼叫超时,设置此参数为整体流程请求的超时时间
    //                    .addInterceptor() //设置拦截器
    //                    .authenticator() //设置认证器
    //                    .proxy()//设置代理
                        .build();
            }
            return mOkHttpClient;
        }
    
        public static void destroy(){
            mOkHttpClient = null;
        }
        
    }
  • 相关阅读:
    iOS 10 因苹果健康导致闪退 crash-b
    iOS10 配置须知-b
    iOS开发 适配iOS10以及Xcode8-b
    iOS 10 的适配问题-b
    mybatis中分页查询
    mybatis开发流程,增删改查
    spring mvc接收参数方式,json格式返回请求数据
    xml配置文件中常见的命名空间解释
    myeclipse中配置schemaLocation路径,实现xml文件自动提示
    spring MVC工作流程
  • 原文地址:https://www.cnblogs.com/guanxinjing/p/9708575.html
Copyright © 2011-2022 走看看