Android okhttp 网络链接各阶段监控

news2024/11/21 21:52:06

步骤 1: 添加依赖

在项目的 build.gradle 文件中,添加 OkHttp 依赖:

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

步骤 2: 创建自定义的 EventListener

创建一个自定义的 EventListener 类:

import android.util.Log
import okhttp3.*
import java.io.IOException
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.Proxy

class LoggingEventListener : EventListener() {
    private var mCallStartTime: Long? = null
    private var mCallEndTime: Long? = null
    private var mDnsStartTime: Long? = null
    private var mDnsEndTime: Long? = null
    private var mConnectStartTime: Long? = null
    private var mSecureConnectStartTime: Long? = null
    private var mSecureConnectEndTime: Long? = null
    private var mConnectEndTime: Long? = null
    private var mRequestHeadersStartTime: Long? = null
    private var mRequestHeadersEndTime: Long? = null
    private var mResponseHeadersStartTime: Long? = null
    private var mResponseHeadersEndTime: Long? = null
    private var mResponseBodyStartTime: Long? = null
    private var mResponseBodyEndTime: Long? = null

    companion object {
        const val TAG = "LoggingEventListener"
    }

    override fun callStart(call: Call) {
        mCallStartTime = System.currentTimeMillis()
        Log.i(TAG, "Event callStart at $mCallStartTime")
    }

    override fun dnsStart(call: Call, domainName: String) {
        mDnsStartTime = System.currentTimeMillis()
        Log.i(TAG, "Event dnsStart at $mDnsStartTime")
    }

    override fun dnsEnd(call: Call, domainName: String, inetAddressList: List<InetAddress>) {
        mDnsEndTime = System.currentTimeMillis()
        Log.i(TAG, "Event dnsEnd at $mDnsEndTime dnsDuration is ${mDnsEndTime!! - mDnsStartTime!!} ms")
    }

    override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy) {
        mConnectStartTime = System.currentTimeMillis()
        Log.i(TAG, "Event connectStart at $mConnectStartTime")
    }

    override fun secureConnectStart(call: Call) {
        mSecureConnectStartTime = System.currentTimeMillis()
        Log.i(TAG, "Event secureConnectStart at $mSecureConnectStartTime")
    }

    override fun secureConnectEnd(call: Call, handshake: Handshake?) {
        mSecureConnectEndTime = System.currentTimeMillis()
        Log.i(TAG, "Event secureConnectEnd at $mSecureConnectEndTime secureConnectDuration is ${mSecureConnectEndTime!! - mSecureConnectStartTime!!} ms")
    }

    override fun connectEnd(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy, protocol: Protocol?) {
        mConnectEndTime = System.currentTimeMillis()
        Log.i(TAG, "Event connectEnd at $mConnectEndTime ConnectDuration is ${mConnectEndTime!! - mConnectStartTime!!} ms")
    }

    override fun requestHeadersStart(call: Call) {
        mRequestHeadersStartTime = System.currentTimeMillis()
        Log.i(TAG, "Event requestHeadersStart at $mRequestHeadersStartTime")
    }

    override fun requestHeadersEnd(call: Call, request: Request) {
        mRequestHeadersEndTime = System.currentTimeMillis()
        Log.i(TAG, "Event requestHeadersEnd at $mRequestHeadersEndTime requestHeadersDuration is ${mRequestHeadersEndTime!! - mRequestHeadersStartTime!!} ms")
    }

    override fun responseHeadersStart(call: Call) {
        mResponseHeadersStartTime = System.currentTimeMillis()
        Log.i(TAG, "Event responseHeadersStart at $mResponseHeadersStartTime")
    }

    override fun responseHeadersEnd(call: Call, response: Response) {
        mResponseHeadersEndTime = System.currentTimeMillis()
        Log.i(TAG, "Event responseHeadersEnd at $mResponseHeadersEndTime responseHeadersDuration is ${mResponseHeadersEndTime!! - mResponseHeadersStartTime!!} ms")
    }

    override fun responseBodyStart(call: Call) {
        mResponseBodyStartTime = System.currentTimeMillis()
        Log.i(TAG, "Event responseBodyStart at $mResponseBodyStartTime")
    }

    override fun responseBodyEnd(call: Call, byteCount: Long) {
        mResponseBodyEndTime = System.currentTimeMillis()
        Log.i(TAG, "Event responseBodyEnd at $mResponseBodyEndTime responseHeadersDuration is ${mResponseBodyEndTime!! - mResponseBodyStartTime!!} ms")
    }

    override fun callEnd(call: Call) {
        mCallEndTime = System.currentTimeMillis()
        Log.i(TAG, "Event callEnd at $mCallEndTime responseHeadersDuration is ${mCallEndTime!! - mCallStartTime!!} ms")
    }

    override fun callFailed(call: Call, ioe: IOException) {
        Log.i(TAG,"Request Failed: ${ioe.message}")
    }
}

步骤 3: 在 MainActivity 中发起网络请求

创建一个简单的 MainActivity,发起 HTTP 请求并使用 LoggingEventListener



import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import okhttp3.*
import java.io.IOException

class MainActivity : AppCompatActivity() {

    companion object {
        const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 创建 OkHttpClient 并设置自定义 EventListener
        val client = OkHttpClient.Builder()
            .eventListener(LoggingEventListener())
            .build()

        // 创建请求对象
        val request = Request.Builder()
            .url("https://jsonplaceholder.typicode.com/posts/1") // 示例 API
            .build()

        // 发起异步网络请求
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                Log.i(TAG, "Request Failed: ${e.message}")
            }

            override fun onResponse(call: Call, response: Response) {
                Log.i(TAG, "Response: ${response.body?.string()}")
            }
        })
    }
}

步骤 4: 添加权限

AndroidManifest.xml 中添加网络权限:

<uses-permission android:name="android.permission.INTERNET" />

步骤 5: 布局文件

创建简单的布局文件 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:padding="16dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="OkHttp EventListener Demo"
        android:textSize="18sp"
        android:textStyle="bold" />
</LinearLayout>

运行结果

运行应用后,打开日志工具(Logcat)可以看到网络请求的各个阶段日志,例如:

I/LoggingEventListener: Event callStart at 1731855030207
I/LoggingEventListener: Event dnsStart at 1731855030212
I/LoggingEventListener: Event dnsEnd at 1731855030213 dnsDuration is 1 ms
I/LoggingEventListener: Event connectStart at 1731855030215
I/LoggingEventListener: Event secureConnectStart at 1731855030581
I/LoggingEventListener: Event secureConnectEnd at 1731855030878 secureConnectDuration is 297 ms
I/LoggingEventListener: Event connectEnd at 1731855030886 ConnectDuration is 671 ms
I/LoggingEventListener: Event requestHeadersStart at 1731855030887
I/LoggingEventListener: Event requestHeadersEnd at 1731855030889 requestHeadersDuration is 2 ms
I/LoggingEventListener: Event responseHeadersStart at 1731855031406
I/LoggingEventListener: Event responseHeadersEnd at 1731855031406 responseHeadersDuration is 0 ms
I/LoggingEventListener: Event responseBodyStart at 1731855031414
I/LoggingEventListener: Event responseBodyEnd at 1731855031415 responseHeadersDuration is 1 ms
I/LoggingEventListener: Event callEnd at 1731855031415 responseHeadersDuration is 1208 ms

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2244900.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MyBatis——#{} 和 ${} 的区别和动态 SQL

1. #{} 和 ${} 的区别 为了方便&#xff0c;接下来使用注解方式来演示&#xff1a; #{} 的 SQL 语句中的参数是用过 ? 来起到类似于占位符的作用&#xff0c;而 ${} 是直接进行参数替换&#xff0c;这种直接替换的即时 SQL 就可能会出现一个问题 当传入一个字符串时&#xff…

【Python】30个Python爬虫的实战项目!!!(附源码)

Python爬虫是数据采集自动化的利器。本文精选了30个实用的Python爬虫项目&#xff0c;从基础到进阶&#xff0c;每个项目都配有完整源码和详细讲解。通过这些项目的实战&#xff0c;可以全面掌握网页数据抓取、反爬处理、并发下载等核心技能。 一、环境准备 在开始爬虫项目前…

深述C++模板类

1、前言 函数模板是通用函数的描述&#xff0c;类模板是通用类的描述&#xff0c;使用任意类型来描述类的定义。和函数模板有很多相似的地方&#xff0c;关于函数模板可以看我之前写过的一篇文章&#xff1a;简述C函数模板。这里就不过多赘述。 2、模板类的基本概念 模板类的…

C语言教程指针笔记整理

https://www.bilibili.com/video/BV1cx4y1d7Ut?spm_id_from333.788.videopod.episodes&vd_sourcee8984989cddeb3ef7b7e9fd89098dbe8&p107 本篇为贺宏宏老师C语言教程指针部分笔记整理 //.c文件 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include …

从二维到一维:动态规划矩阵问题的优化之道

动态规划中的矩阵问题是非常经典的应用场景&#xff0c;比如最小路径和问题。这类问题很自然地可以想到使用二维 dp 数组来求解。 我们定义&#xff1a; dp[i][j] 表示从矩阵的第 i行第 j列到右下角的最小路径和。 基本解法 求解过程从右下角开始&#xff0c;向左上角遍历&am…

git,ssh免密公钥配置,gitee为例,GitHub,gitlab同理

git&#xff0c;ssh免密公钥配置&#xff0c;gitee为例&#xff0c;视频教程在这 git&#xff0c;ssh免密公钥配置&#xff0c;gitee为例&#xff0c;GitHub&#xff0c;gitlab同理_哔哩哔哩_bilibili 一、进入.ssh目录 cd ~/.ssh 二、查看是否有id_rsa.pub这个文件 分为…

Spring Boot整合Kafka,实现单条消费和批量消费,示例教程

如何安装Kafka&#xff0c;可以参考docker搭载Kafka集群&#xff0c;一个文件搞定&#xff0c;超简单&#xff0c;亲试可行-CSDN博客 1、在pom.xml中加入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-sta…

基于Vue+SpringBoot的求职招聘平台

平台概述 本平台是一个高效、便捷的人才与职位匹配系统&#xff0c;旨在为求职者与招聘者提供一站式服务。平台内设三大核心角色&#xff1a;求职者、招聘者以及超级管理员&#xff0c;每个角色拥有独特的功能模块&#xff0c;确保用户能够轻松完成从信息获取到最终录用的整个…

FPGA FIFO系列 - FIFO使用中需要注意的若干问题

FIFO使用中需要注意的若干问题 文章目录 FIFO使用中需要注意的若干问题前言场景1&#xff1a;包数据FIFO设计之冗余法场景2、FIFO数据传输之流控总结 前言 场景1&#xff1a;包数据FIFO设计之冗余法 场景&#xff1a;类似图像、文字等码流数据是不需要重复被访问的&#xff0c…

.NET 9 - BinaryFormatter移除

1.简单介绍 .NET 9 SDK正式版已经发布, 下载地址是.NET9 同时.NET Conf 2024 大会已经从2024-11-13开始了&#xff0c;感觉Aspire和AI的内容相对挺多的&#xff0c;主题分享演示时候打开的网站大部分都是Blazor制作的。 这次.NET Conf 2024老师也再次说明了一下&#xff0c;…

[免费]SpringBoot+Vue毕业设计论文管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue毕业设计论文管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue毕业设计论文管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 现代经济快节奏发展以及不断完善升级的信…

C# 高级--反射 详解

一、反射是什么 1、C#编译运行过程 高级语言->编译->dll/exe文件->CLR/JIT->机器码 2、原理解析metadata&#xff1a;元数据数据清单&#xff0c;记录了dll中包含了哪些东西,是一个描述。IL&#xff1a;中间语言&#xff0c;编译把高级语言编译后得到的C#中最真…

OpenCV与AI深度学习|16个含源码和数据集的计算机视觉实战项目(建议收藏!)

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;分享&#xff5c;16个含源码和数据集的计算机视觉实战项目 本文将分享16个含源码和数据集的计算机视觉实战项目。具体包括&#xff1a; 1. 人…

【软考网工笔记】网络基础理论——应用层

TLv 基本编码规则&#xff08;BER&#xff09;将ASN.1表示的抽象类型值编码为字节串&#xff0c;这种字节串的结构为&#xff1a;类型——长度——值&#xff0c;简称TLv。 其中&#xff0c;值部分还可以递归的在编码为TLv结构&#xff0c;一具有表达复杂结构的能力。 IP地址…

用Python爬虫“偷窥”1688商品详情:一场数据的奇妙冒险

引言&#xff1a;数据的宝藏 在这个信息爆炸的时代&#xff0c;数据就像是一座座等待挖掘的宝藏。而对于我们这些电商界的探险家来说&#xff0c;1688上的商品详情就是那些闪闪发光的金子。今天&#xff0c;我们将化身为数据的海盗&#xff0c;用Python这把锋利的剑&#xff0…

企业网络安全规划建设实践

规划是指较全面或长远的计划。凡事预则立&#xff0c;不预则废&#xff01; 在企业战略规划方面&#xff0c;随着市场环境变化速度的不断加快&#xff0c;人们越来越意识到企业战略规划对企业生存和发展的重要性&#xff0c;战略规划能帮助企业解决影响组织未来发展最重要、最…

QT基本绘图

QT绘图 1.概述 这篇文章介绍如何绘图 2.绘图基本操作 创建一个普通的widget类型的项目 在widget.h 文件中重写绘图事件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : p…

Linux驱动开发(7):使用设备树实现RGB 灯驱动

通过上一小节的学习&#xff0c;我们已经能够编写简单的设备树节点&#xff0c;并且使用常用的of函数从设备树中获取我们想要的节点资源。 这一小节我们带领大家使用设备树编写一个简单的RGB灯驱动程序&#xff0c;加深对设备树的理解。 1. 实验说明 本节实验使用到 EBF6ULL-…

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk)

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk) 1.计算模型介绍 使用GARCH&#xff08;广义自回归条件异方差&#xff09;模型计算VaR&#xff08;风险价值&#xff09;时&#xff0c;方差法是一个常用的方法。GARCH模型能够捕捉到金融时间序列数据中的波…

Neo4j下载及其Cypher语法介绍

1.部署安装 Neo4j支持众多平台的部署安装&#xff0c;如&#xff1a;Windows、Mac、Linux等系统。Neo4j是基于Java平台的&#xff0c;所以部署安装前先保证已经安装了Java虚拟机。 在神领物流项目中&#xff0c;我们采用docker的方式进行安装。安装命令如下&#xff1a; dock…