关于okhttp:OkHttp请求耗时统计

62次阅读

共计 20001 个字符,预计需要花费 51 分钟才能阅读完成。

目录介绍

  • 01. 先发问一个问题
  • 02.EventListener 回调原理
  • 03. 申请开始完结监听
  • 04.dns 解析开始完结监听
  • 05. 连贯开始完结监听
  • 06.TLS 连贯开始完结监听
  • 07. 连贯绑定和开释监听
  • 08.request 申请监听
  • 09.response 响应监听
  • 10. 如何监听统计耗时
  • 11. 利用实际之案例

01. 先发问一个问题

  • OkHttp 如何进行各个申请环节的耗时统计呢?

    • OkHttp 版本提供了 EventListener 接口,能够让调用者接管一系列网络申请过程中的事件,例如 DNS 解析、TSL/SSL 连贯、Response 接管等。
    • 通过继承此接口,调用者能够监督整个利用中网络申请次数、流量大小、耗时 (比方 dns 解析工夫,申请工夫,响应工夫等等) 状况。

02.EventListener 回调原理

  • 先来看一下

    public abstract class EventListener {
       // 依照申请程序回调
        public void callStart(Call call) {}
        // 域名解析
        public void dnsStart(Call call, String domainName) {}
        public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {}
        // 开释以后 Transmitter 的 RealConnection
        public void connectionReleased(Call call, Connection connection) {}
        public void connectionAcquired(call, result){};
        // 开始连贯
        public void connectStart(call, route.socketAddress(), proxy){}
        // 申请
        public void requestHeadersStart(@NotNull Call call){}
        public void requestHeadersEnd(@NotNull Call call, @NotNull Request request) {}
        // 响应
        public void requestBodyStart(@NotNull Call call) {}
        public void requestBodyEnd(@NotNull Call call, long byteCount) {}
        // 完结
        public void callEnd(Call call) {}
        // 失败
        public void callFailed(Call call, IOException ioe) {}}

03. 申请开始完结监听

  • callStart(Call call) 申请开始

    • 当一个 Call(代表一个申请)被同步执行或被增加异步队列中时,即会调用这个回调办法。
    • 须要阐明这个办法是在 dispatcher.executed/enqueue 前执行的。
    • 因为线程或事件流的限度,这里的申请开始并不是真正的去执行的这个申请。如果产生重定向和多域名重试时,这个办法也仅被调用一次。
    final class RealCall implements Call {
        @Override 
        public Response execute() throws IOException {eventListener.callStart(this);
            client.dispatcher().executed(this);
            Response result = getResponseWithInterceptorChain();
            if (result == null) throw new IOException("Canceled");
            return result;    
        }
    
        @Override 
        public void enqueue(Callback responseCallback) {eventListener.callStart(this);
            client.dispatcher().enqueue(new AsyncCall(responseCallback));
        }
    }
  • callFailed/callEnd 申请异样和申请完结

    • 每一个 callStart 都对应着一个 callFailed 或 callEnd。
    • callFailed 在两种状况下被调用,第一种是在申请执行的过程中产生异样时。第二种是在申请完结后,敞开输出流时产生异样时。
    final class RealCall implements Call {
        @Override 
        public Response execute() throws IOException {
            try {client.dispatcher().executed(this);
              Response result = getResponseWithInterceptorChain();
              if (result == null) throw new IOException("Canceled");
              return result;
            } catch (IOException e) {eventListener.callFailed(this, e);
              throw e;
            }
        }
        final class AsyncCall extends NamedRunnable {
            @Override 
            protected void execute() {
                try {Response response = getResponseWithInterceptorChain();
                } catch (IOException e) {eventListener.callFailed(RealCall.this, e);
    
                }
            }
        }
    }
    
    // 第二种
    public final class StreamAllocation {public void streamFinished(boolean noNewStreams, HttpCodec codec, long bytesRead, IOException e) {
            ...
            if (e != null) {eventListener.callFailed(call, e);
            } else if (callEnd) {eventListener.callEnd(call);
            }
            ...
        }
    }
    • callEnd 也有两种调用场景。第一种也是在敞开流时。第二种是在开释连贯时。
    public final class StreamAllocation {public void streamFinished(boolean noNewStreams, HttpCodec codec, long bytesRead, IOException e) {
            ...
            if (e != null) {eventListener.callFailed(call, e);
            } else if (callEnd) {eventListener.callEnd(call);
            }
            ...
        }
    
        public void release() {
            ...
            if (releasedConnection != null) {eventListener.connectionReleased(call, releasedConnection);
              eventListener.callEnd(call);
            }
        }
    }
    • 为什么会将敞开流和敞开连接区离开?

      • 在 http2 版本中,一个连贯上容许关上多个流,OkHttp 应用 StreamAllocation 来作为流和连贯的桥梁。当一个流被敞开时,要查看这条连贯上还有没有其余流,如果没有其余流了,则能够将连贯敞开了。
      • streamFinished 和 release 作用是一样的,都是敞开以后流,并查看是否须要敞开连贯。不同的是,当调用者手动勾销申请时,调用的是 release 办法,并由调用者负责敞开申请输入流和响应输出流。

04.dns 解析开始完结监听

  • dnsStart 开始

    • 其中的 lookup(String hostname)办法代表了域名解析的过程,dnsStart/dnsEnd 就是在 lookup 前后被调用的
    • DNS 解析是申请 DNS(Domain Name System)服务器,将域名解析成 ip 的过程。域名解析工作是由 JDK 中的 InetAddress 类实现的。
      /** Prepares the socket addresses to attempt for the current proxy or host. */
      private void resetNextInetSocketAddress(Proxy proxy) throws IOException {if (proxy.type() == Proxy.Type.SOCKS) {inetSocketAddresses.add(InetSocketAddress.createUnresolved(socketHost, socketPort));
        } else {eventListener.dnsStart(call, socketHost);
    
          // Try each address for best behavior in mixed IPv4/IPv6 environments.
          List<InetAddress> addresses = address.dns().lookup(socketHost);
          if (addresses.isEmpty()) {throw new UnknownHostException(address.dns() + "returned no addresses for" + socketHost);
          }
    
          eventListener.dnsEnd(call, socketHost, addresses);
        }
      }
  • 那么 RouteSelector 这个类是在哪里调用

    public final class StreamAllocation {
    
      public StreamAllocation(ConnectionPool connectionPool, Address address, Call call,
          EventListener eventListener, Object callStackTrace) {this.routeSelector = new RouteSelector(address, routeDatabase(), call, eventListener);
      }
    }

05. 连贯开始完结监听

  • connectStart 连贯开始

    • OkHttp 是应用 Socket 接口建设 Tcp 连贯的,所以这里的连贯就是指 Socket 建设一个连贯的过程。
    • 当连贯被重用时,connectStart/connectEnd 不会被调用。当申请被重定向到新的域名后,connectStart/connectEnd 会被调用屡次。
      private void connectSocket(int connectTimeout, int readTimeout, Call call,
          EventListener eventListener) throws IOException {Proxy proxy = route.proxy();
        Address address = route.address();
    
        rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
            ? address.socketFactory().createSocket()
            : new Socket(proxy);
    
        eventListener.connectStart(call, route.socketAddress(), proxy);
      }
  • connectEnd 连贯完结

    • 因为创立的连贯有两种类型(服务端直连和隧道代理),所以 callEnd 有两处调用地位。为了在基于代理的连贯上应用 SSL,须要独自发送 CONECT 申请。
    • 在连贯过程中,无论是 Socket 连贯失败,还是 TSL/SSL 握手失败,都会回调 connectEnd。
      public void connect(int connectTimeout, int readTimeout, int writeTimeout,
        while (true) {
          try {establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener);
            eventListener.connectEnd(call, route.socketAddress(), route.proxy(), protocol);
            break;
          } catch (IOException e) {eventListener.connectFailed(call, route.socketAddress(), route.proxy(), null, e);
          }
      }
    
      private void connectTunnel(int connectTimeout, int readTimeout, int writeTimeout, Call call,
          EventListener eventListener) throws IOException {Request tunnelRequest = createTunnelRequest();
        HttpUrl url = tunnelRequest.url();
        for (int i = 0; i < MAX_TUNNEL_ATTEMPTS; i++) {connectSocket(connectTimeout, readTimeout, call, eventListener);
          eventListener.connectEnd(call, route.socketAddress(), route.proxy(), null);
        }
      }

06.TLS 连贯开始完结监听

  • 开始连贯,代码如下所示

    • 在下面看到,在 Socket 建设连贯后,会执行一个 establishProtocol 办法,这个办法的作用就是 TSL/SSL 握手。
    • 当存在重定向或连贯重试的状况下,secureConnectStart/secureConnectEnd 会被调用屡次。
      private void establishProtocol(ConnectionSpecSelector connectionSpecSelector,
          int pingIntervalMillis, Call call, EventListener eventListener) throws IOException {if (route.address().sslSocketFactory() == null) {
          protocol = Protocol.HTTP_1_1;
          socket = rawSocket;
          return;
        }
    
        eventListener.secureConnectStart(call);
        connectTls(connectionSpecSelector);
        eventListener.secureConnectEnd(call, handshake);
      }
  • 联合连贯监听可知

    • 如果咱们应用了 HTTPS 平安连贯,在 TCP 连贯胜利后须要进行 TLS 平安协定通信,等 TLS 通信完结后能力算是整个连贯过程的完结,也就是说 connectEnd 在 secureConnectEnd 之后调用。
  • 所以程序是这样的

    • connectStart —> secureConnectStart —> secureConnectEnd —> ConnectEnd

07. 连贯绑定和开释监听

  • 因为 OkHttp 是基于连贯复用的,当一次申请完结后并不会马上敞开以后连贯,而是放到连接池中。

    • 当有雷同域名的申请时,会从连接池中取出对应的连贯应用,缩小了连贯的频繁创立和销毁。
    • 当依据一个申请从连接池取连贯时,并关上输入输出流就是 acquired,用完开释流就是 released。
    • 如果间接复用 StreamAllocation 中的连贯,则不会调用 connectionAcquired/connectReleased。
      private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
          int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {synchronized (connectionPool) {if (result == null) {
            // 第一次查缓存 Attempt to get a connection from the pool.
            // Attempt to get a connection from the pool.
            Internal.instance.get(connectionPool, address, this, null);
          }
        }
    
        if (releasedConnection != null) {eventListener.connectionReleased(call, releasedConnection);
        }
        if (foundPooledConnection) {eventListener.connectionAcquired(call, result);
        }
    
        synchronized (connectionPool) {if (canceled) throw new IOException("Canceled");
    
          if (newRouteSelection) {
            // 第二次查缓存
            List<Route> routes = routeSelection.getAll();
            for (int i = 0, size = routes.size(); i < size; i++) {Route route = routes.get(i);
              Internal.instance.get(connectionPool, address, this, route);
              if (connection != null) {
                foundPooledConnection = true;
                result = connection;
                this.route = route;
                break;
              }
            }
          }
    
          if (!foundPooledConnection) {
            // 如果缓存没有,则新建连贯
            route = selectedRoute;
            refusedStreamCount = 0;
            result = new RealConnection(connectionPool, selectedRoute);
            acquire(result, false);
          }
        }
    
        // If we found a pooled connection on the 2nd time around, we're done.
        if (foundPooledConnection) {eventListener.connectionAcquired(call, result);
          return result;
        }
    
        // Do TCP + TLS handshakes. This is a blocking operation.
        result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
            connectionRetryEnabled, call, eventListener);
        routeDatabase().connected(result.route());
    
        eventListener.connectionAcquired(call, result);
        return result;
      }
  • connectionAcquired 是在连贯胜利后被调用的。

    • 然而在连贯复用的状况下没有连贯步骤,connectAcquired 会在获取缓存连贯后被调用。因为 StreamAllocation 是连贯“Stream”和“Connection”的桥梁,所以在 StreamAllocation 中会持有一个 RealConnection 援用。StreamAllocation 在查找可用连贯的程序为:StreamAllocation.RealConnection -> ConnectionPool -> ConnectionPool -> new RealConnection

08.request 申请监听

  • 在 OkHttp 中,HttpCodec 负责对申请和响应依照 Http 协定进行编解码,蕴含发送申请头、发送申请体、读取响应头、读取响应体。
  • requestHeaders 开始和完结,这个间接看 CallServerInterceptor 拦截器代码即可。

    public final class CallServerInterceptor implements Interceptor {@Override public Response intercept(Chain chain) throws IOException {RealInterceptorChain realChain = (RealInterceptorChain) chain;
        HttpCodec httpCodec = realChain.httpStream();
        StreamAllocation streamAllocation = realChain.streamAllocation();
        RealConnection connection = (RealConnection) realChain.connection();
        Request request = realChain.request();
    
        long sentRequestMillis = System.currentTimeMillis();
    
        realChain.eventListener().requestHeadersStart(realChain.call());
        httpCodec.writeRequestHeaders(request);
        realChain.eventListener().requestHeadersEnd(realChain.call(), request);
        
        if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {if (responseBuilder == null) {
            // Write the request body if the "Expect: 100-continue" expectation was met.
            realChain.eventListener().requestBodyStart(realChain.call());
            long contentLength = request.body().contentLength();
            CountingSink requestBodyOut =
                new CountingSink(httpCodec.createRequestBody(request, contentLength));
            BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
    
            request.body().writeTo(bufferedRequestBody);
            bufferedRequestBody.close();
            realChain.eventListener().requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
          } 
        }
        return response;
      }
    }

09.response 响应监听

  • responseHeadersStart 和 responseHeadersEnd 代码如下所示

    public final class CallServerInterceptor implements Interceptor {@Override public Response intercept(Chain chain) throws IOException {
    
        Response.Builder responseBuilder = null;
        if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {httpCodec.flushRequest();
            realChain.eventListener().responseHeadersStart(realChain.call());
            responseBuilder = httpCodec.readResponseHeaders(true);
          }
        }
    
        httpCodec.finishRequest();
    
        if (responseBuilder == null) {realChain.eventListener().responseHeadersStart(realChain.call());
          responseBuilder = httpCodec.readResponseHeaders(false);
        }
    
        int code = response.code();
        if (code == 100) {
          // server sent a 100-continue even though we did not request one.
          // try again to read the actual response
          responseBuilder = httpCodec.readResponseHeaders(false);
    
          response = responseBuilder
                  .request(request)
                  .handshake(streamAllocation.connection().handshake())
                  .sentRequestAtMillis(sentRequestMillis)
                  .receivedResponseAtMillis(System.currentTimeMillis())
                  .build();
    
          code = response.code();}
    
        realChain.eventListener() .responseHeadersEnd(realChain.call(), response);
        return response;
      }
    }
  • responseBodyStart 监听

    • 响应体的读取有些简单,要依据不同类型的 Content-Type 决定如何读取响应体,例如固定长度的、基于块 (chunk) 数据的、未知长度的。具体看 openResponseBody 办法外面的代码。
    • 同时 Http1 与 Http2 也有不同的解析形式。上面以 Http1 为例。
    public final class Http1Codec implements HttpCodec {@Override public ResponseBody openResponseBody(Response response) throws IOException {streamAllocation.eventListener.responseBodyStart(streamAllocation.call);
        String contentType = response.header("Content-Type");
    
        if (!HttpHeaders.hasBody(response)) {Source source = newFixedLengthSource(0);
          return new RealResponseBody(contentType, 0, Okio.buffer(source));
        }
    
        if ("chunked".equalsIgnoreCase(response.header("Transfer-Encoding"))) {Source source = newChunkedSource(response.request().url());
          return new RealResponseBody(contentType, -1L, Okio.buffer(source));
        }
    
        long contentLength = HttpHeaders.contentLength(response);
        if (contentLength != -1) {Source source = newFixedLengthSource(contentLength);
          return new RealResponseBody(contentType, contentLength, Okio.buffer(source));
        }
    
        return new RealResponseBody(contentType, -1L, Okio.buffer(newUnknownLengthSource()));
      }
    }
  • responseBodyEnd 监听

    • 由上面代码可知,当响应完结后,会调用连贯 callEnd 回调(如果异样则会调用 callFailed 回调)
    public final class StreamAllocation {public void streamFinished(boolean noNewStreams, HttpCodec codec, long bytesRead, IOException e) {eventListener.responseBodyEnd(call, bytesRead);
        if (releasedConnection != null) {eventListener.connectionReleased(call, releasedConnection);
        }
        if (e != null) {eventListener.callFailed(call, e);
        } else if (callEnd) {eventListener.callEnd(call);
        }
      }
    }

10. 如何监听统计耗时

  • 如何耗费记录时间

    • 在 OkHttp 库中有一个 EventListener 类。该类是网络事件的侦听器。扩大这个类以监督应用程序的 HTTP 调用的数量、大小和持续时间。
    • 所有启动 / 连贯 / 获取事件最终将接管到匹配的完结 / 开释事件,要么胜利(非空参数),要么失败(非空可抛出)。
    • 比方,能够在开始链接记录时间;dns 开始,完结等办法解析记录时间,能够计算 dns 的解析工夫。
    • 比方,能够在开始申请记录时间,记录 connectStart,connectEnd 等办法工夫,则能够计算出 connect 连接时间。
  • 代码如下所示

    • Eventlistener 只实用于没有并发的状况,如果有多个申请并发执行咱们须要应用 Eventlistener. Factory 来给每个申请创立一个 Eventlistener。
    • 这个 mRequestId 是惟一值,能够抉择应用 AtomicInteger 自增 + 1 的形式设置 id,这个应用了 cas 保障多线程条件下的原子性个性。
    /**
     * <pre>
     *     @author yangchong
     *     email  : yangchong211@163.com
     *     time  : 2019/07/22
     *     desc  : EventListener 子类
     *     revise:
     * </pre>
     */
    public class NetworkListener extends EventListener {
    
        private static final String TAG = "NetworkEventListener";
        private static AtomicInteger mNextRequestId = new AtomicInteger(0);
        private String mRequestId ;
    
        public static Factory get(){Factory factory = new Factory() {
                @NotNull
                @Override
                public EventListener create(@NotNull Call call) {return new NetworkListener();
                }
            };
            return factory;
        }
    
        @Override
        public void callStart(@NotNull Call call) {super.callStart(call);
            //mRequestId = mNextRequestId.getAndIncrement() + "";
            //getAndAdd,在多线程下应用 cas 保障原子性
            mRequestId = String.valueOf(mNextRequestId.getAndIncrement());
            ToolLogUtils.i(TAG+"-------callStart---requestId-----"+mRequestId);
            saveEvent(NetworkTraceBean.CALL_START);
            saveUrl(call.request().url().toString());
        }
    
        @Override
        public void dnsStart(@NotNull Call call, @NotNull String domainName) {super.dnsStart(call, domainName);
            ToolLogUtils.d(TAG, "dnsStart");
            saveEvent(NetworkTraceBean.DNS_START);
        }
    
        @Override
        public void dnsEnd(@NotNull Call call, @NotNull String domainName, @NotNull List<InetAddress> inetAddressList) {super.dnsEnd(call, domainName, inetAddressList);
            ToolLogUtils.d(TAG, "dnsEnd");
            saveEvent(NetworkTraceBean.DNS_END);
        }
    
        @Override
        public void connectStart(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy) {super.connectStart(call, inetSocketAddress, proxy);
            ToolLogUtils.d(TAG, "connectStart");
            saveEvent(NetworkTraceBean.CONNECT_START);
        }
    
        @Override
        public void secureConnectStart(@NotNull Call call) {super.secureConnectStart(call);
            ToolLogUtils.d(TAG, "secureConnectStart");
            saveEvent(NetworkTraceBean.SECURE_CONNECT_START);
        }
    
        @Override
        public void secureConnectEnd(@NotNull Call call, @Nullable Handshake handshake) {super.secureConnectEnd(call, handshake);
            ToolLogUtils.d(TAG, "secureConnectEnd");
            saveEvent(NetworkTraceBean.SECURE_CONNECT_END);
        }
    
        @Override
        public void connectEnd(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress,
                               @NotNull Proxy proxy, @Nullable Protocol protocol) {super.connectEnd(call, inetSocketAddress, proxy, protocol);
            ToolLogUtils.d(TAG, "connectEnd");
            saveEvent(NetworkTraceBean.CONNECT_END);
        }
    
        @Override
        public void connectFailed(@NotNull Call call, @NotNull InetSocketAddress inetSocketAddress, @NotNull Proxy proxy, @Nullable Protocol protocol, @NotNull IOException ioe) {super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe);
            ToolLogUtils.d(TAG, "connectFailed");
        }
    
        @Override
        public void requestHeadersStart(@NotNull Call call) {super.requestHeadersStart(call);
            ToolLogUtils.d(TAG, "requestHeadersStart");
            saveEvent(NetworkTraceBean.REQUEST_HEADERS_START);
        }
    
        @Override
        public void requestHeadersEnd(@NotNull Call call, @NotNull Request request) {super.requestHeadersEnd(call, request);
            ToolLogUtils.d(TAG, "requestHeadersEnd");
            saveEvent(NetworkTraceBean.REQUEST_HEADERS_END);
        }
    
        @Override
        public void requestBodyStart(@NotNull Call call) {super.requestBodyStart(call);
            ToolLogUtils.d(TAG, "requestBodyStart");
            saveEvent(NetworkTraceBean.REQUEST_BODY_START);
        }
    
        @Override
        public void requestBodyEnd(@NotNull Call call, long byteCount) {super.requestBodyEnd(call, byteCount);
            ToolLogUtils.d(TAG, "requestBodyEnd");
            saveEvent(NetworkTraceBean.REQUEST_BODY_END);
        }
    
        @Override
        public void responseHeadersStart(@NotNull Call call) {super.responseHeadersStart(call);
            ToolLogUtils.d(TAG, "responseHeadersStart");
            saveEvent(NetworkTraceBean.RESPONSE_HEADERS_START);
        }
    
        @Override
        public void responseHeadersEnd(@NotNull Call call, @NotNull Response response) {super.responseHeadersEnd(call, response);
            ToolLogUtils.d(TAG, "responseHeadersEnd");
            saveEvent(NetworkTraceBean.RESPONSE_HEADERS_END);
        }
    
        @Override
        public void responseBodyStart(@NotNull Call call) {super.responseBodyStart(call);
            ToolLogUtils.d(TAG, "responseBodyStart");
            saveEvent(NetworkTraceBean.RESPONSE_BODY_START);
        }
    
        @Override
        public void responseBodyEnd(@NotNull Call call, long byteCount) {super.responseBodyEnd(call, byteCount);
            ToolLogUtils.d(TAG, "responseBodyEnd");
            saveEvent(NetworkTraceBean.RESPONSE_BODY_END);
        }
    
        @Override
        public void callEnd(@NotNull Call call) {super.callEnd(call);
            ToolLogUtils.d(TAG, "callEnd");
            saveEvent(NetworkTraceBean.CALL_END);
            generateTraceData();
            NetWorkUtils.timeoutChecker(mRequestId);
        }
    
        @Override
        public void callFailed(@NotNull Call call, @NotNull IOException ioe) {super.callFailed(call, ioe);
            ToolLogUtils.d(TAG, "callFailed");
        }
    
        private void generateTraceData(){NetworkTraceBean traceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
            Map<String, Long> eventsTimeMap = traceModel.getNetworkEventsMap();
            Map<String, Long> traceList = traceModel.getTraceItemList();
            traceList.put(NetworkTraceBean.TRACE_NAME_TOTAL,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.CALL_START, NetworkTraceBean.CALL_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_DNS,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.DNS_START, NetworkTraceBean.DNS_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_SECURE_CONNECT,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.SECURE_CONNECT_START, NetworkTraceBean.SECURE_CONNECT_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_CONNECT,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.CONNECT_START, NetworkTraceBean.CONNECT_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_REQUEST_HEADERS,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.REQUEST_HEADERS_START, NetworkTraceBean.REQUEST_HEADERS_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_REQUEST_BODY,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.REQUEST_BODY_START, NetworkTraceBean.REQUEST_BODY_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_RESPONSE_HEADERS,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.RESPONSE_HEADERS_START, NetworkTraceBean.RESPONSE_HEADERS_END));
            traceList.put(NetworkTraceBean.TRACE_NAME_RESPONSE_BODY,NetWorkUtils.getEventCostTime(eventsTimeMap,NetworkTraceBean.RESPONSE_BODY_START, NetworkTraceBean.RESPONSE_BODY_END));
        }
    
        private void saveEvent(String eventName){NetworkTraceBean networkTraceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
            Map<String, Long> networkEventsMap = networkTraceModel.getNetworkEventsMap();
            networkEventsMap.put(eventName, SystemClock.elapsedRealtime());
        }
    
        private void saveUrl(String url){NetworkTraceBean networkTraceModel = IDataPoolHandleImpl.getInstance().getNetworkTraceModel(mRequestId);
            networkTraceModel.setUrl(url);
        }
    
    }
  • 对于执行程序,打印后果如下所示

    2020-09-22 20:50:15.351 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: dnsStart
    2020-09-22 20:50:15.373 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: dnsEnd
    2020-09-22 20:50:15.374 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: connectStart
    2020-09-22 20:50:15.404 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: secureConnectStart
    2020-09-22 20:50:15.490 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: secureConnectEnd
    2020-09-22 20:50:15.490 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: connectEnd
    2020-09-22 20:50:15.492 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: requestHeadersStart
    2020-09-22 20:50:15.492 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: requestHeadersEnd
    2020-09-22 20:50:15.528 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: responseHeadersStart
    2020-09-22 20:50:15.528 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: responseHeadersEnd
    2020-09-22 20:50:15.532 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: responseBodyStart
    2020-09-22 20:50:15.534 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: responseBodyEnd
    2020-09-22 20:50:15.547 28144-28277/cn.com.zwwl.bayuwen D/NetworkEventListener: callEnd

11. 利用实际之案例





  • 网络拦挡剖析,次要是剖析网络流量损耗,以及 request,respond 过程工夫。打造网络分析工具……
  • 我的项目代码地址:https://github.com/yangchong2…
  • 如果你感觉这个拦挡网络助手不便了测试,以及开发中查看网络数据,能够 star 一下……

网络拦挡库:https://github.com/yangchong2…

正文完
 0