Android Okhttp3《一》

前言

OkHttp 就不做多余的介绍了,可说说是目前使用最广泛的网络请求框架,在很多的其他第三方框架中也是用了改网络请求框架例如Retrofit,这里主要想说一些问什么使用okhttp。

一、为什么使用版OKHttp

1.1 Socket

如果我们需要从服务器获取一个资源,那么就一定需要访问网络,访问网络就一定需要使用到Socket,我想大家在学习Java的网络编程的时候也就是Socket 编程的时候一定写过客户端与服务端,客户端法一个消息然后服务端返回一个消息,就是一个极为简单的聊天软件,理论上我们可以通过Socket 访问网络 获取任何我们需要的资源,Sokcet 给用户提供了网络访问的通道,但是没有提供通信的协议。 目前我们最常用的通信协议是Http。

1.2 Http

关于Http 也不想多费口舌,Http的协议内容是固定的,但是Http协议在不同语言或者是不同框架上实现的方式与支持力度是不一样的,这就延伸出了很多的问题。

我记得最开始学习Http的时候,我们还曾经自己通过Sokcet 实现最简单的Http协议

    private static void doGet(String host, int port, String uri) {
        Socket socket=null;
        try {
            socket=new Socket(host,port);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            StringBuffer sb=new StringBuffer("GET "+uri+" HTTP/1.1\r\n");
            sb.append("Accept: */*\r\n");
            sb.append("Accept-Language: zh-cn\r\n");
            sb.append("User-Agent: HTTPClient\r\n");
            sb.append("Host: localhost:8080\r\n");
            sb.append("Connection: Keep-Alive\r\n");

            //send http request
            OutputStream socketOut=socket.getOutputStream();
            socketOut.write(sb.toString().getBytes());

            Thread.sleep(2000);//sleep 2s ,wait response

            //recieve
            InputStream socketIn=socket.getInputStream();
            int size=socketIn.available();
            byte[] buffer=new byte[size];
            socketIn.read(buffer);
            System.out.println(new String(buffer));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }

上面就是最简单的Http 的get 请求,当然也实现了对应的Post的请求这里就不在贴出来了,我们一度很困惑,既然自己实现了Http协议,为什么还要使用别的框架,自己实现的难道不是更简单节约吗,说实在的我真的困惑的很长一段时间,现在看来这真的是一个很愚蠢的问题。

我产生这个困惑并且迟迟没有没能像明白的原因是因为在大多数的开发里面,我们访问网络仅仅是我发出一个请求,服务器将数据返回来就可以了,中间没有根本没有重定向,数据缓存,cookie ,数据压缩,以及其他Http的错误码的处理。实际上直到现在对于大部分app而言获取数据也是这样,如果使用了第三方的api另当别论。

后来随着开发时间长了才渐渐明白这些东西。如果仅仅考虑自己的一个App也许可以使用上那个最简单的实现方法,但是考虑到日后的维护与扩展,这样一个简单的实现明显是不行的。
一个框架除了考虑对整个Http协议支持的完整度,(如是否支持HTTPS,HTTP2,是否支持代理,是否支持Cookie)还要考虑实现的方式与实现的效率。(例如Sokcet的链接复用以便提高链接速度,API的友好性等等。)

最终在一系列竞争中OkHttp 获得了胜利。 关于OkHttp 与其他的网络框架例如Volley 的对比大家可以自行搜索一下。

二、OKHttp 请求过程

    void test() throws IOException {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();

        OkHttpClient client = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)//连接失败后是否重新连接
                .connectTimeout(15, TimeUnit.SECONDS)//超时时间15S
                .build();

        String url = "http://124.205.184.180:8080/up/Upload?flg=0";
        Request request = new Request.Builder()
                .url(url).build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });
    }

如上,这里对于OkHttpClient 的创建过程不做介绍,无非是配置各种参数。主要从创建请求开始

  @Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }

newCall 创建一个请求,返回的是Call的实现类RealCall,下面进入RealCall的enqueue 方法

  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

dispatch 返回一个分发器Dispatcher,Dispatcher 可以看成是对线程池的封装,可以控制同时并发请求的数量等,

  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

如果当前正在执行的请求数量小于配置的最大请求,同时当前Host的请求数量小于配置的数量,此时就会将请求抛到线程池等待执行,

AsyncCall 是对RealCall的装饰,同时AsyncCall 实现了Runnable 接口,所以抛到线程池之后最终会调用到AsyncCall 的run 方法
在这里插入图片描述

在这里插入图片描述

run 方法最终调用的是execute 方法

    @Override 
    protected void execute() {
      boolean signalledCallback = false;
      try {
      //访问网络,获取返回结果
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          //调用用户的回调接口,通知失败
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          //调用用户的回调接口,通知获取成功
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }

核心内容是在getResponseWithInterceptorChain

  private Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!retryAndFollowUpInterceptor.isForWebSocket()) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(
        retryAndFollowUpInterceptor.isForWebSocket()));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

getResponseWithInterceptorChain 里面可以看到大名鼎鼎的责任链。

这里拦截器分为两部分
retryAndFollowUpInterceptor 之前的称之为应用拦截器,下面的这一部分是网络拦截器

    if (!retryAndFollowUpInterceptor.isForWebSocket()) {
      interceptors.addAll(client.networkInterceptors());
    }

应用拦截器与网络拦截器的区别:
之前在网上也查询过一些解释,大都是你抄我,我吵他,最终也都没有给出一个很清晰的解释,实际一般情形下二者没啥区别都会执行一次,但是如果涉及到重定向,或者说url对应多个ip地址,当第一个ip地址不可用,此时okhttp也会尝试链接第二个ip, 而这一部分功能都包含在RetryAndFollowUpInterceptor 里面,RetryAndFollowUpInterceptor 可能会调用多次proceed 方法,而没调用一次proceed 方法,在RetryAndFollowUpInterceptor 后面的拦截器都会执行一次,因此此时网络拦截器会多次执行。

关于拦截器的内容就先介绍这么多,具体的下一章介绍。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OkHttp3是一个用于Android应用程序的网络请求框架,它提供了一个简单而强大的API,可以用来发送和接收HTTP请求。为了更好地使用OkHttp3来进行网络请求,我们可以创建一个OkHttp3工具类。 首先,我们需要在项目中添加OkHttp3的依赖。可以通过在build.gradle文件中引入以下依赖来实现: ``` implementation 'com.squareup.okhttp3:okhttp:4.9.2' ``` 然后,我们可以创建一个OkHttp3工具类,该工具类封装了发送和接收网络请求的相关方法。下面是一个简单的示例: ```java import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import java.io.IOException; public class OkHttp3Utils { private OkHttpClient client; public OkHttp3Utils() { client = new OkHttpClient(); } public void sendRequest(String url, Callback callback) { Request request = new Request.Builder() .url(url) .build(); client.newCall(request).enqueue(callback); } } ``` 在这个示例中,我们创建了一个OkHttpClient实例,并提供了一个sendRequest方法来发送网络请求。我们可以将此类实例化并调用sendRequest方法来发送GET或POST请求,并在回调中处理服务器的响应结果。 使用这样的工具类,我们可以更方便地管理和处理网络请求,从而提高Android应用程序的性能和可维护性。当然,还可以根据实际项目的需求来扩展和完善这个工具类,以满足更复杂的网络请求操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值