网络连接基础知识

1、HTTP协议回顾:

01,HTTP协议概述

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

02,HTTP是HyperText 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:请求查询服务器的性能,或者查询与资源相关的选项

GET方式(以在请求的URL地址后以?的形式带上交给服务器的数据,多个数据之间以&进行分隔,通常传送的数据不超过1kb),
通过请求URI得到资源。一般用于获取/查询资源信息

POST方式(在请求的正文内容中向服务器发送数据,传送的数据无限制),
用于向服务器提交新的内容。一般用于更新资源信息

06,状态码

200(正常),206请求部分数据
302/307(临时重定向),
304(未修改),
403(访问被拒绝) -- user-Aqent
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:主机的唯一表示
端口号:正在运行的程序
协议:通信规则,TCP以及UDP

02、网络模型

ISO模型:
    应用层
    会话层
    表示层
    网络层
    传输层
    数据链路层
    物理层

    TCP/IP模型:
    应用层
    网际层
    数据层
    物理层

03、TCP与UDP区别:

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

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

04、Socket以及Http:

Socket:长连接
Http:短连接

05、网络通信中的具体内部细节

URL地址、IP地址:
http://www.abc.com:80/abc/index.html
http://202.108.22.5/

①客户端执行网络请求,从URL中解析出服务器的主机名
②将服务器的主机名转换成服务器的IP地址 (DNS域名解析)
③从URL中将端口号解析出来
④建立一条客户端与Web服务器的TCP连接
⑤客户端通过输出流向服务器发送一条Http请求
⑥服务器向客户端回送一条Http响应报文
⑦客户端从输入流获取报文
⑧客户端解析报文,关闭连接
⑨客户端将结果显示在UI上

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"), "");


    //2.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");
        }
    };

   //3.POST方式提交表单
    RequestBody requestBody4 = new FormBody.Builder()
            .add("pno", "1")
            .add("ps","50")
            .add("dtype","son")
            .add("key","4a7cf244fd7efbd17ecbf0cb8e4d1c85")
            .build();

    //4.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.缓存拦截器

在 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350