OkHttp

作者: Anwfly | 来源:发表于2019-03-28 23:11 被阅读32次

    1、HTTP协议回顾:

    01,HTTP协议概述

    WEB浏览器与WEB服务器之间的一问一答的交互过程必须遵循一定的规则,这个规则就是HTTP协议。

    02,HTTP是 Transfer Protocol(超文本传输协议)

    它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据 的过程及数据本身的格式。
    Http协议是一种应用层协议,它通过TCP实现了可靠的数据传输,能够保证数据的完整性、正确性,
    而TCP对于数据传输控制的优点也能够体现在Http协议上,使得Http的数据传输吞吐量、效率得到保证

    03,请求格式(用火狐看源码)

    • 请求:

    请求行 : 请求方式 请求路径 版本
    请求头 : 以key-value形式组成,K:V。。。
    空行
    请求体 : 用于数据传递:get方式没有请求体(参数地址传递) post方式有请求体

    • 响应:

    响应行 :版本 响应码 响应信息
    响应头 :以key-value形式组成,K:V。。。
    空行
    响应体 :响应正文

    04,常用请求头

    Host: www.baidu.com
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
    Accept-Encoding: gzip, deflate, br
    Connection: keep-alive
    Cache-Control: max-age=0
    Content-Type: text/html
    Content-Length:120

    05,请求方式

    Get:请求获取Request-URI所标识的资源
    POST:在Request-URI所标识的资源后附加新的数据
    HEAD 请求获取由Request-URI所标识的资源的响应信息报头
    PUT:请求服务器存储一个资源,并用Request-URI作为其标识
    DELETE:请求服务器删除Request-URI所标识的资源
    TRACE:请求服务器回送收到的请求信息,主要用于测试或诊断
    CONNECT:保留将来使用
    OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项

    注意:

    1. GET方式(以在请求的URL地址后以?的形式带上交给服务器的数据,多个数据之间以&进行分隔,通常传送的数据不超过1kb),
      通过请求URI得到资源。一般用于获取/查询资源信息
    2. POST方式(在请求的正文内容中向服务器发送数据,传送的数据无限制),
      用于向服务器提交新的内容。一般用于更新资源信息

    06,状态码

    200(正常),206请求部分数据
    302/307(临时重定向),
    304(未修改),
    404(找不到),
    500(服务器内部错误)

    06Http协议的特点

    1、支持客户/服务器模式。
    2、简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、 HEAD、POST。每种方法规定了客户与服务器联系的类型不同。 由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
    3、灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
    4、无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求, 并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
    5、无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。 缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每 次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快

    07Http 1.0 与 Http1.1的区别

    1.0协议,客户端与web服务器建立连接后,只能获得一个web资源! 而1.1协议,允许客户端与web服务器建立连接后,在一个连接上获取多个web资源!

    2、网络通信

    01、网络三要素

    IP:主机的唯一表示 (http://202.108.22.5/)
    端口号:正在运行的程序(0~65535)
    协议:通信规则,TCP以及UDP

    02、网络模型

    2.1 简介

    • 定义:计算机网络的各层 + 其协议的集合
    • 作用:定义该计算机网络的所能完成的功能

    2.2 结构介绍

    • OSI体系结构:概念清楚 & 理念完整,但复杂 & 不实用

    • TCP / IP体系结构:含了一系列构成互联网基础的网络协议,是Internet的核心协议 & 被广泛应用于局域网 和 广域网

    • 五层体系结构:融合了OSI 与 TCP / IP的体系结构,目的是为了学习 & 讲解计算机原理

    网络模型

    03、TCP与UDP区别:

    • TCP:
      建立连接
      安全可靠协议
      以流进行数据传递,无大小限制
      三次握手协议

    • UDP:
      不建立连接
      不可靠协议
      以数据包传递,有大小限制64K

    04、Socket以及Http:

    Socket:长连接
    Http:短连接

    3、异步和同步的区别

    • 同步:就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事;

    • 异步:当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者;

    同步是阻塞模式,异步是非阻塞模式
    同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
    异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式

    4、HttpURlconnection发送网络请求:

    ###01,get请求
    //子线程中执行请求
    URL url = new URL(path);
    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("GET");
        urlConnection.setConnectTimeout(5000);
        if (urlConnection.getResponseCode() == 200){
            InputStream inputStream = urlConnection.getInputStream();
            
        }
    

    02,post请求

    //子线程中执行请求
    URL url = new URL(path);
    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
    urlConnection.setRequestMethod("POST");
    urlConnection.setConnectTimeout(5000);
    urlConnection.setReadTimeout(5000);
    String content = "name="+URLEncoder.encode(name)+"&pass="+URLEncoder.encode(pass);//数据编解码
    urlConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");//设置请求头
    urlConnection.setRequestProperty("Content-Length",content.length()+"");
    urlConnection.setDoOutput(true);
    OutputStream outputStream = urlConnection.getOutputStream();
    outputStream.write(content.getBytes());
    if (urlConnection.getResponseCode() == 200){ }
    

    03,json解析:

    json解析

    bean:
        JSONObject jsonObject = new JSONObject(text);
        String code = jsonObject.getString("resultCode");
    
    array:
        ArrayList<StuClzInfo> list = new ArrayList<>();
        JSONArray array = new JSONArray(text);
        for (int i = 0; i < array.length(); i++) {
                StuClzInfo info = new StuClzInfo();
                JSONObject object = array.getJSONObject(i);
                info.setCode(object.getString("code"));
                info.setCount(object.getInt("count"));
                list.add(info);
        }
    
        
    bean中带array:
        JSONObject object = new JSONObject(text);
            String resultCode = object.getString("resultCode");
            if ("1".equals(resultCode)) {
                tv_name.setText(object.getString("school"));
                JSONArray clazz = object.getJSONArray("clazz");
                List<StuClzInfo> list = new ArrayList<>();
                for (int i = 0; i < clazz.length(); i++) {
                    JSONObject o = clazz.getJSONObject(i);
                    StuClzInfo info = new StuClzInfo();
                    info.setCode(o.getString("code"));
                    info.setCount(o.getInt("count"));
                    list.add(info);
                }
            }
    

    gson解析(bean,array,bean中带array)

    bean:
        Gson gson = new Gson();
        LoginInfo loginInfo = gson.fromJson(text, LoginInfo.class);//bean
        
    array:
        Gson gson = new Gson();
        Type type = new TypeToken<List<StuClzInfo>>() {}.getType();
        List<StuClzInfo> list = gson.fromJson(text, type);//list<bean>
        
    bean中带array:
        SchoolInfo info = gson.fromJson(text, SchoolInfo.class);
        list = info.getClazz();//bean.list<bean>
    

    fastjson解析(bean,array,bean中带array)

    bean:
        LoginInfo loginInfo1 = JSON.parseObject(text, LoginInfo.class);
    
    array:
        List<StuClzInfo> list = JSON.parseArray(text, StuClzInfo.class);
        
    bean中带array:
        SchoolInfo info = JSON.parseObject(text, SchoolInfo.class);
        List<StuClzInfo> list = info.getClazz();
    

    5,OkHttp3讲解

    01,OkHttp3简介

    1.支持http和https协议,api相同,易用;
    2.http使用线程池,https使用多路复用;
    3.okhttp支持同步和异步调用;
    4.支持普通form和文件上传form;
    5.操作请求和响应(日志,请求头,body等);
    6.okhttp可以设置缓存;
    7.支持透明的gzip压缩响应体

    02,OkHttp3 配置

    1,Android Studio 配置gradle:
    implementation 'com.squareup.okhttp3:okhttp:3.12.0'
    2,添加网络权限:
    <uses-permission android:name="android.permission.INTERNET"/>

    03,OkHttp3 使用思路

    get请求思路

    1.获取okHttpClient对象
    2.构建Request对象
    3.构建Call对象
    4.通过Call.enqueue(callback)方法来提交异步请求;execute()方法实现同步请求

    post请求思路

    1.获取okHttpClient对象
    2.创建RequestBody
    3.构建Request对象
    4.构建Call对象
    5.通过Call.enqueue(callback)方法来提交异步请求;execute()方法实现同步请求

    04,OkHttp3 发送异步请求(GET)

        String url = "http://";
    
        //第一步获取okHttpClient对象
        OkHttpClient client = new OkHttpClient.Builder()
                .build();
        //第二步构建Request对象
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        //第三步构建Call对象
        Call call = client.newCall(request);
        //第四步:异步get请求
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i("onFailure", e.getMessage());
            }
    
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                Log.i("result", result);
            }
        });
    

    04,OkHttp3 发送同步请求(GET)

        String url = "http://";
    
        //第一步获取okHttpClient对象
        OkHttpClient client = new OkHttpClient.Builder()
                .build();
        //第二步构建Request对象
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        //第三步构建Call对象
        final Call call = client.newCall(request);
        //第四步:同步get请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response response = call.execute();//必须子线程执行
                    String result = response.body().string();
                    Log.i("response", result);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    

    05,OkHttp3 发送异步请求(POST)

        //接口参数 String username,String password
    
        String url = "http://";
        //第一步创建OKHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
                .build();
        //第二步创建RequestBody(Form表达)
        RequestBody body = new FormBody.Builder()
                .add("username", "admin")
                .add("password", "123456")
                .build();
        //第三步创建Rquest
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        //第四步创建call回调对象
        final Call call = client.newCall(request);
        //第五步发起请求
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i("onFailure", e.getMessage());
            }
    
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                Log.i("result", result);
            }
        });
    

    05,OkHttp3 发送同步请求(POST)

        //接口参数 String username,String password
    
        String url = "http://";
        //第一步创建OKHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
                .build();
        //第二步创建RequestBody
        RequestBody body = new FormBody.Builder()
                .add("username", "admin")
                .add("password", "123456")
                .build();
        //第三步创建Rquest
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        //第四步创建call回调对象
        final Call call = client.newCall(request);
        //第五步发起请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response response = call.execute();
                    String result = response.body().string();
                    Log.i("response", result);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start(); 
    

    06, 请求头处理(Header)以及超时和缓冲处理以及响应处理

        //超时设置
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(5,TimeUnit.SECONDS)//设置连接时间
                .readTimeout(5,TimeUnit.SECONDS)//设置读取时间
                .writeTimeout(5,TimeUnit.SECONDS)//设置写出时间
                .cache(new Cache(cacheDirectory,10*1024*1024))
                .build();
    
        //表单提交
        RequestBody requestBody = new FormBody.Builder()
                .add("pno", "1")
                .add("ps","50")
                .add("dtype","son")
                .add("key","4a7cf244fd7efbd17ecbf0cb8e4d1c85")
                .build();
    
        //请求头设置
        Request request = new Request.Builder()
                .url(url)
                .addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
                .header("User-Agent", "OkHttp Example")
                .post(body)
                .build();
      
        //响应处理
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            //响应行
            Log.d("ok", response.protocol() + " " +response.code() + " " + response.message());
            //响应头
            Headers headers = response.headers();
            for (int i = 0; i < headers.size(); i++) {
                Log.d("ok", headers.name(i) + ":" + headers.value(i));
            }
            //响应体
            final String string = response.body().string();
    
            Log.d("ok", "onResponse: " + string);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    tx.setText(string);
                }
            });
        }
    

    07, 请求体处理(Form表单,String字符串,流,文件)

    1. POST方式提交String/JSON application/json;json串
    MediaType mediaType1 = MediaType.parse("application/x-www-form-urlencoded;charset=utf-8");
    String requestBody = "pno=1&ps=50&dtype=son&key=4a7cf244fd7efbd17ecbf0cb8e4d1c85";
            RequestBody requestBody1 = RequestBody.create(mediaType1, requestBody);
    
    //POST方式提交JSON:传递JSON同时设置son类型头(接口找一下)
    RequestBody requestBodyJson = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), "{}");
    request.addHeader("Content-Type", "application/json")//必须加json类型头
                
    //POST方式提交无参
    RequestBody requestBody1 = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=utf-8"), "");
    
    
    1. POST方式提交流
    RequestBody requestBody2 = new RequestBody() {
                @Nullable
                @Override
                public MediaType contentType() {
                    return MediaType.parse("application/x-www-form-urlencoded;charset=utf-8");
                }
    
                @Override
                public void writeTo(BufferedSink sink) throws IOException {
                    sink.writeUtf8("pno=1&ps=50&dtype=son&key=4a7cf244fd7efbd17ecbf0cb8e4d1c85");
                }
            };
    
    1. POST方式提交表单
    RequestBody requestBody4 = new FormBody.Builder()
                    .add("pno", "1")
                    .add("ps","50")
                    .add("dtype","son")
                    .add("key","4a7cf244fd7efbd17ecbf0cb8e4d1c85")
                    .build();
    
    1. POST提交文件
    MediaType mediaType3 = MediaType.parse("text/x-markdown; charset=utf-8");
            File file = new File("test.txt");
            RequestBody requestBody3 = RequestBody.create(mediaType3, file);
    
            //5.POST方式提交分块请求
            MultipartBody body = new MultipartBody.Builder("AaB03x")
                    .setType(MultipartBody.FORM)
                    .addPart(
                            Headers.of("Content-Disposition", "form-data; name=\"title\""),
                            RequestBody.create(null, "Square Logo"))
                    .addPart(
                            Headers.of("Content-Disposition", "form-data; name=\"image\""),
                            RequestBody.create(MediaType.parse("image/png"), new File("website/static/logo-square.png")))
                    .build();
    

    08, 拦截器:网络拦截器,缓存拦截器,日志拦截器,重定向拦截器

    一、Application Intercetor和NetworkInterceptor的区别

    1,Application interceptors 应用拦截器
    builder.addInterceptor(new LoggingInterceptor())
    
    Application Interceptor 是第一个 Interceptor 因此它会被第一个执行,因此这里的 request 还是最原始的。而对于 response 而言呢,因为整个过程是递归的调用过程,因此它会在 CallServerInterceptor 执行完毕之后才会将 Response 进行返回,因此在 Application Interceptor 这里得到的 response 就是最终的响应,虽然中间有重定向,但是这里只关心最终的 response
    
    1,不需要去关心中发生的重定向和重试操作。因为它处于第一个拦截器,会获取到最终的响应 
    2,只会被调用一次,即使这个响应是从缓存中获取的。
    3,只关注最原始的请求,不去关系请求的资源是否发生了改变,我只关注最后的 response 结果而已。
    4,因为是第一个被执行的拦截器,因此它有权决定了是否要调用其他拦截,也就是 Chain.proceed() 方法是否要被执行。
    5,因为是第一个被执行的拦截器,因此它有可以多次调用 Chain.proceed() 方法,其实也就是相当与重新请求的作用了。
    
    2,Network Interceptors 网络拦截器
    builder.addNetworkInterceptor(new LoggingInterceptor())
    
    NetwrokInterceptor 处于第 6 个拦截器中,它会经过 RetryAndFollowIntercptor 进行重定向并且也会通过 BridgeInterceptor 进行 request 请求头和 响应 resposne 的处理,因此这里可以得到的是更多的信息。在打印结果可以看到它内部是发生了一次重定向操作,在上图可以看出,为什么 NetworkInterceptor 可以比 Application Interceptor 得到更多的信息了
    
    1,因为 NetworkInterceptor 是排在第 6 个拦截器中,因此可以操作经过 RetryAndFollowup 进行失败重试或者重定向之后得到的resposne。
    2,对于从缓存获取的 response 则不会去触发 NetworkInterceptor 。因为响应直接从 CacheInterceptor 返回了。
    3,观察数据在网络中的传输。
    4,可以获得装载请求的连接。
    

    二、拦截器的应用

    1.日志拦截器

    在 LoggingInterceptor 中主要做了 3 件事:
    1,请求前-打印请求信息;
    2,网络请求-递归去调用其他拦截器发生网络请求;
    3,网络响应后-打印响应信息

    代码:

        OkHttpClient client = builder
                    .addInterceptor(new LoggingInterceptor())//应用拦截器
                    .addNetworkInterceptor(new LoggingInterceptor())//网络拦截器
                    .readTimeout(5, TimeUnit.SECONDS)
                    .connectTimeout(5, TimeUnit.SECONDS)
                    .writeTimeout(5, TimeUnit.SECONDS)
                    .build();
    
        class LoggingInterceptor implements Interceptor {
    
            private static final String TAG = "LoggingInterceptor";
    
            @Override
            public Response intercept(Chain chain) throws IOException {
         
                Request request = chain.request();
    
                //1.请求前--打印请求信息
                long startTime = System.nanoTime();
                Log.d(TAG, String.format("Sending request %s on %s%n%s",
                        request.url(), chain.connection(), request.headers()));
    
                //2.网络请求
                Response response =  chain.proceed(request);
    
                //3.网络响应后--打印响应信息
                long endTime = System.nanoTime();
                Log.d(TAG, String.format("Received response for %s in %.1fms%n%s",
                        response.request().url(), (endTime - startTime) / 1e6d, response.headers()));
    
                return response;
            }
        }
    
    2.缓存拦截器(通过adb命令查看data数据)

    在 MyCacheinterceptor 中主要做了(post方式无法缓存)
    1,设置缓存位置
    2,无网时:设置缓存协议
    3,有网:加载网络数据;无网:加载缓存数据

    代码:

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(myCacheinterceptor)//应用拦截器
                    .addNetworkInterceptor(myCacheinterceptor)//网络拦截器
                    .connectTimeout(5, TimeUnit.SECONDS)
                    .cache(new Cache(new File(getCacheDir(), "Cache"), 1024 * 1024 * 10))
                    .build();
    
        class MyCacheinterceptor implements Interceptor {
            @Override
            public Response intercept(Chain chain) throws IOException {
    
                Request request = chain.request();
       
                if (!isNetworkAvailable(MainActivity.this)) {
                    request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
    
                }
    
                Response originalResponse = chain.proceed(request);
    
                if (isNetworkAvailable(MainActivity.this)) {
                    int maxAge = 0;
                    return originalResponse.newBuilder()
                            .removeHeader("Pragma")
                            .header("Cache-Control", "public ,max-age=" + maxAge)
                            .build();
                } else {
                    int maxStale = 15*60;
                    return originalResponse.newBuilder()
                            .removeHeader("Pragma")
                            .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                            .build();
                }
    
            }
        }
    
        /**
            检测是否有网
         */
        public static boolean isNetworkAvailable(Context context) {
            if (context != null) {
                ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo info = cm.getActiveNetworkInfo();
                if (info != null) {
                    return info.isAvailable();
                }
            }
            return false;
        }
    

    09注意事项

    1,推荐让 OkHttpClient 保持单例,用同一个 OkHttpClient 实例来执行你的所有请求,因为每一个 OkHttpClient 实例都拥有自己的连接池和线程池,重用这些资源可以减少延时和节省资源,如果为每个请求创建一个 OkHttpClient 实例,显然就是一种资源的浪费。
    
    2,response.body().string()只调用一次
    
    3,每一个Call(其实现是RealCall)只能执行一次,否则会报异常
    
    4,子线程加载数据后,主线程刷新数据
    

    10,HttpURLconnection及OkHttp3的对比分析

    1,HttpUrlConnection,google官方提供的用来访问网络,但是实现的比较简单,只支持1.0/1.1
    2,并没有多路复用,如果碰到app大量网络请求的时候,性能比较差,
    3,HttpUrlConnection底层也是用Socket来实现的
    4,OkHttp像HttpUrlConnection一样,实现了一个网络连接的过程。
    5,OkHttp和HttpUrlConnection是一级的,用socket实现了网络连接,OkHttp更强大,
    6,HttpUrlConnection在IO方面用到的是InputStream和OutputStream,但OkHttp用的是sink和source,这两个是在Okio这个开源库里的,    feredSink(支持缓冲)、GzipSink(支持Gzip压缩)、ForwardingSink和InflaterSink(后面这两者服务于GzipSink)
    7,多个相同host和port的stream可以共同使用一个socket,而RealConnection就是处理连接的,那也就是说一个RealConnection上可能有很多个Stream
    8,OkHttp代码比HttpURLConnection精简的多
    

    11,OkHttp源码分析(设计模式,线程池的使用)

    4.单利、多线程安全问题

    /**
      饿汉式
     */
    public class Person {
    
        //1.构造函数私有化
        private Person(){}
    
        //2.创建单个私有对象对象
        private static  Person person = new Person();
    
        //3.提供对外公开访问方法
        public static Person getPerson() {
            return person;
        }
    }
    
    /**
     * 懒汉式
     *
     * 多线程安全问题:
     *      1.多个线程同时操作
     *      2.共用同一个资源
     *      3.分步执行操作同一个资源
     *
     * 多线程安全解决方式:
     *      1.同步方法
     *      2.同步代码块
     *      3.锁机制
     */
    public class Student {
    
        //1.构造函数私有化
        private Student(){}
    
        //2.创建单个私有对象对象
        private static  Student student;
    
        //3.提供对外公开访问方法
        public static Student getInstance(){
    
            //解决线程安全问题
            if (student == null){
                synchronized (Student.class){
                    if (student == null) {
                        student = new Student();
                    }
                }
            }
    
            return student;
        }
    }
    

    5.OkHttpUtils工具类抽取

    public class OkHttpUtils {
    
        private static OkHttpUtils okHttpUtils;
        private static OkHttpClient okHttpClient;
        private static Handler mHandler;
    
        /**
         * 构造初始化
         */
        private OkHttpUtils(){
            /**
             * 构建OkHttpClient
             */
            okHttpClient = new OkHttpClient.Builder()
            /**
             * 请求的超时时间
             */
            .readTimeout(5000, TimeUnit.MILLISECONDS)
            /**
             * 设置响应的超时时间
             */
            .writeTimeout(5000, TimeUnit.MILLISECONDS)
            /**
             * 设置连接的超时时间
             */
            .connectTimeout(5000, TimeUnit.MILLISECONDS)
            /**
             * 构建
             */
            .build();
    
    
            /**
             * 获取主线程的handler
             */
            mHandler = new Handler(Looper.getMainLooper());
        }
    
        /**
         * 通过单例模式构造对象
         * @return
         */
        public static OkHttpUtils getInstance(){
            if (OkHttpUtils == null){
                synchronized (OkHttpUtils.class){
                    if (okHttpUtils == null){
                        okHttpUtils = new OkHttpUtils();
                    }
                }
            }
            return okHttpUtils;
        }
    
        /**
         * 构造Get请求,封装对用的Request请求,实现方法
         * @param url  访问路径
         * @param realCallback  接口回调
         */
        private void getRequest(String url, final RealCallback realCallback){
    
            Request request = new Request.Builder().url(url).get().build();
            deliveryResult(realCallback, okHttpClient.newCall(request));
        }
    
        /**
         * 构造post 请求,封装对用的Request请求,实现方法
         * @param url 请求的url
         * @param requestBody 请求参数
         * @param realCallback 结果回调的方法
         */
        private void postRequest(String url, RequestBody requestBody, final RealCallback realCallback){
    
            Request request = new Request.Builder().url(url).post(requestBody).build();
            deliveryResult(realCallback, okHttpClient.newCall(request));
        }
    
        /**
         * 处理请求结果的回调:主线程切换
         * @param realCallback
         * @param call
         */
        private void deliveryResult(final RealCallback realCallback, Call call) {
            call.enqueue(new Callback() {
                @Override
                public void onFailure(final Call call, final IOException e) {
                    sendFailureThread(call, e, realCallback);
                }
    
                @Override
                public void onResponse(final Call call, final Response response) throws IOException {
                    sendSuccessThread(call, response, realCallback);
                }
            });
        }
    
        /**
         * 发送成功的回调
         * @param call
         * @param response
         * @param realCallback
         */
        private void sendSuccessThread(final Call call, final Response response, final RealCallback
                realCallback) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    realCallback.onResponse(call,response);
                }
            });
        }
    
        /**
         * 发送失败的回调
         * @param call
         * @param e
         * @param realCallback
         */
        private void sendFailureThread(final Call call, final IOException e, final RealCallback realCallback) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    realCallback.onFailure(call,e);
                }
            });
        }
    
        //-----------对外公共访问的get/post方法-----------
        /**
         * get请求
         * @param url  请求url
         * @param realCallback  请求回调
         */
        public void get(String url, final RealCallback realCallback){
            getRequest(url,realCallback);
        }
    
        /**
         * post请求
         * @param url       请求url
         * @param realCallback  请求回调
         * @param requestBody    请求参数
         */
        public void post(String url, RequestBody requestBody, final RealCallback realCallback){
            postRequest(url,requestBody,realCallback);
        }
    
        /**
         * http请求回调类,回调方法在UI线程中执行
         */
        public static abstract class RealCallback {
            /**
             * 请求成功回调
             * @param response
             */
            public abstract void onResponse(Call call,Response response);
            /**
             * 请求失败回调
             * @param e
             */
            public abstract void onFailure(Call call,IOException e);
        }
    }
    

    6,xRecyclerView

    相关文章

      网友评论

        本文标题:OkHttp

        本文链接:https://www.haomeiwen.com/subject/dsmcbqtx.html