当前位置: 首页 > news >正文

Aspect Android埋点统计activity页面使用时长 onResume onPause,并保存时长

Aspect Android埋点统计activity页面使用时长 onResume onPause,并保存时长

标记:

1.项目下build.gradle

dependencies {classpath 'com.android.tools.build:gradle:3.5.4'classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'
}

2.app 文件夹下 build.gradle

apply plugin: 'com.hujiang.android-aspectjx'

// 配置 AspectJX
aspectjx {exclude 'androidx.core','androidx.appcompat'
}

dependencies {.......// 引入 AspectJX 依赖implementation 'org.aspectj:aspectjrt: 1.9.8'
...
}

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Mainandroid.applicationVariants.all { variant ->JavaCompile javaCompile = variant.javaCompilejavaCompile.doLast {//下面的1.8是指我们兼容的jdk的版本String[] args = ["-showWeaveInfo","-1.8","-inpath", javaCompile.destinationDir.toString(),"-aspectpath", javaCompile.classpath.asPath,"-d", javaCompile.destinationDir.toString(),"-classpath", javaCompile.classpath.asPath,"-bootclasspath", android.bootClasspath.join(File.pathSeparator)]MessageHandler handler = new MessageHandler(true);new Main().run(args, handler)def log = project.loggerfor (IMessage message : handler.getMessages(null, true)) {switch (message.getKind()) {case IMessage.ABORT:case IMessage.ERROR:case IMessage.FAIL:log.error message.message, message.thrownbreak;case IMessage.WARNING:case IMessage.INFO:log.info message.message, message.thrownbreak;case IMessage.DEBUG:log.debug message.message, message.thrownbreak;}}}
}

注意:

aspectjx {。。。}   和
android.applicationVariants.all {。。。。。}
要与   android {...} 同级

示例:


@Aspect
public class ClickAspect {private static final String TAG = ClickAspect.class.getSimpleName();private Map<String, Long> resumeTimeMap = new WeakHashMap<>();private Map<String, Long> durationMap = new WeakHashMap<>();private Map<String, Boolean> eventTrackerMap = new WeakHashMap<>();@Pointcut("execution(* android.view.View.OnClickListener.onClick(android.view.View))")public void onClickPointcut() {}@Pointcut("execution(* android.app.Activity.onCreate(..))")public void activityOnCreatePointcut() {}@Pointcut("execution(* bg.camera.com.MainActivity+.onDestroy(..))")public void activityDestroyPointcut() {}// 定义切入点,匹配Activity的onResume和onDestroy方法@Pointcut("execution(void android.app.Activity.onResume()) && target(activity)")public void onActivityResumed(Activity activity) {}@Pointcut("execution(void android.app.Activity.onPause()) && target(activity)")public void onActivityPaused(Activity activity) {}@Pointcut("execution(void android.app.Activity.onDestroy()) && target(activity)")public void onActivityDestroy(Activity activity) {}// 在Activity的onCreate方法前进行统计逻辑处理@Before("onActivityResumed(activity)")public void trackActivityResumed(JoinPoint joinPoint, Activity activity) {// 获取Activity的类名String className = activity.getClass().getSimpleName();// 获取当前时间戳long startTime = System.currentTimeMillis();// 存储Activity的开始时间戳// 可以使用SharedPreferences或其他方式进行持久化存储updateTrackPointInfoNameValue(activity, className, startTime);Log.i(TAG, activity.getClass().getSimpleName() + " onActivityResumed "+startTime);}// 在Activity的onDestroy方法后进行统计逻辑处理@After("onActivityPaused(activity)")public void trackActivityPaused(JoinPoint joinPoint, Activity activity) {// 获取Activity的类名String className = activity.getClass().getSimpleName();EventBean starTimeE = getTrackPointInfoNameValue(activity, className);long starTime = null != starTimeE ? starTimeE.getEventTime() : 0;// 获取停留当前时间戳long pausedTime = System.currentTimeMillis() - starTime;// 获取存储的开始时间戳// 根据开始时间戳和当前时间戳计算使用时长// 进行统计上报或其他处理逻辑updateTrackPointInfoNameValue(activity, className, pausedTime);Log.i(TAG, activity.getClass().getSimpleName() + " onActivityPaused "+pausedTime);}// 在Activity的onDestroy方法后进行统计逻辑处理@After("onActivityDestroy(activity)")public void trackActivityDestroy(JoinPoint joinPoint, Activity activity) {// 获取Activity的类名String className = activity.getClass().getSimpleName();removeTrackPointInfoNameValue(activity, System.currentTimeMillis());Log.i(TAG, activity.getClass().getSimpleName() + " onActivityPaused");// 注销之后Fragment onStop之后的生命周期将不再执行// 进行统计上报或其他处理逻辑}@After("onClickPointcut()")public void afterOnClick(JoinPoint joinPoint) throws Throwable {Object target = joinPoint.getTarget();String className = "";if (target != null) {className = target.getClass().getSimpleName();}Object[] args = joinPoint.getArgs();if (args.length > 0 && args[0] instanceof View) {View view = (View) args[0];String entryName = view.getResources().getResourceEntryName(view.getId());
//            TrackPoint.onClick(className, entryName);}
//        joinPoint.proceed();// 点击事件执行后执行的代码Log.d(TAG, "Button clicked");}@Around("activityOnCreatePointcut()")public void pageOpen(ProceedingJoinPoint joinPoint) throws Throwable {String name = joinPoint.getSignature().toShortString();long time = System.currentTimeMillis();Object target = joinPoint.getTarget();String className = target.getClass().getSimpleName();
//        updateTrackPointInfoNameValue(activity, className, 0L);
//        TrackPoint.onPageOpen(className);joinPoint.proceed();Log.e(TAG, name + " activityOnCreatePointcut: " + (System.currentTimeMillis() - time));}@Around("activityDestroyPointcut()")public void pageClose(ProceedingJoinPoint joinPoint) throws Throwable {long time = System.currentTimeMillis();Object target = joinPoint.getTarget();String className = target.getClass().getSimpleName();
//        TrackPoint.onPageClose(className);joinPoint.proceed();Log.e(TAG, className + " activityOnCreatePointcut: " + (System.currentTimeMillis() - time));}public static boolean hasId(int[] arr, int value) {for (int i : arr) {if (i == value)return true;}return false;}/*** 性能监控** AspectJ其实在Android中的应用主要还是性能监控、日志埋点等,下面以一个简单的例子表示:* 我们监控布局加载耗时,判断布局是否嵌套过多或者过于复制导致Activity启动卡顿,首先我们知道Activity是通过setContentView方法加载布局的:* 1、布局解析过程,IO过程* 2、创建View为反射过程* 这两步均为耗时操作,所以我们需要监控setContentView** 日常开发中,我们可以将耗时上传到服务器,收集用户信息,找到卡顿Activity做出对应优化* @param point* @throws Throwable*/@Around("execution(* android.app.Activity.setContentView(..))")public void getContentViewTime(ProceedingJoinPoint point) throws Throwable {String name = point.getSignature().toShortString();long time = System.currentTimeMillis();point.proceed();Log.e(TAG, name + " cost: " + (System.currentTimeMillis() - time));}@Around("call (* bg.eyccamera.com.MyApp.**(..))")public void getTime(ProceedingJoinPoint joinPoint) {Signature signature = joinPoint.getSignature();String name = signature.toShortString();long time = System.currentTimeMillis();try {joinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}Log.i(TAG, name + " cost" + (System.currentTimeMillis() - time));}private void updateTrackPointInfoNameValue(Context context, String name, long time) {DatabaseManager.getInstance(context).insertData(new EventBean(name, time));}private EventBean getTrackPointInfoNameValue(Context context, String name) {return getTrackPointInfoNameValue(context, name, 0);}private EventBean getTrackPointInfoNameValue(Context context, String name, long time) {List<EventBean> eventList = null;EventBean eventBean = null;eventList = DatabaseManager.getInstance(context).getAllData();if (null != eventList && eventList.size() > 0) {for (int i = 0; i < eventList.size(); i++) {if (name.equals(eventList.get(i).getPath())) {eventBean = eventList.get(i);break;}}}return eventBean;}private void removeTrackPointInfoNameValue(Context context, long evenTime) {DatabaseManager.getInstance(context).removeData(evenTime/ 1000);}
}

相关文章:

Aspect Android埋点统计activity页面使用时长 onResume onPause,并保存时长

Aspect Android埋点统计activity页面使用时长 onResume onPause&#xff0c;并保存时长 标记&#xff1a; 1.项目下build.gradle dependencies {classpath com.android.tools.build:gradle:3.5.4classpath com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10 } 2.…...

第四章 选择结构程序设计

C语言有两种选择语句&#xff1a;&#xff08;1&#xff09;if语句&#xff0c;实现两个分支的选择结构&#xff1b; &#xff08;2&#xff09;Switch语句&#xff0c;实现多分支的选择结构。 1.求ax^2bxc0方程的解。 #include<stdio.h> #include<math.h> int …...

JAVA高级教程-Java List(2)

目录 3、List接口的使用&#xff08;1&#xff09;3、List接口的使用&#xff08;3&#xff09;4、排序&#xff0c;集合之间的转换 3、List接口的使用&#xff08;1&#xff09; package ArrayList01;import java.util.ArrayList; import java.util.Iterator; import java.ut…...

Spark--经典SQL50题

目录 连接数据库准备工作 1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数 2、查询"01"课程比"02"课程成绩低的学生的信息及课程分数 3、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩 4、查询平均成绩…...

数据结构: AVL树

目录 1.AVL树的概念 2.AVL树的模拟实现 AVL树的结构定义 插入 对平衡因子的讨论 旋转 对旋转情况的讨论 1.单旋 1.1左单旋 1.2右单旋 2.双旋 2.1左右双旋 2.2右左双旋 检查是否是AVL树 1.AVL树的概念 当向二叉搜索树中插入新结点后&#xff0c;如果能保证每个结点…...

LeetCode-高频 SQL 50 题:连接 篇

目录 1378. 使用唯一标识码替换员工ID 题目描述&#xff1a; SQL语句&#xff1a; 1068. 产品销售分析 I 题目描述&#xff1a; SQL语句&#xff1a; 1581. 进店却未进行过交易的顾客 题目描述&#xff1a; SQL语句&#xff1a; 197. 上升的温度 题目描述&#xff1…...

操作系统备考学习 day10

操作系统备考学习 day10 第三章 内存管理3.2 虚拟内存管理3.2.1 虚拟内存的基本概念传统存储管理方式的特征、缺点局部性原理虚拟内存的定义和特征如何实现虚拟内存技术 3.2.2 请求分页管理方式页表机制缺页中断机构地址变换机构 3.2.3 页面置换算法最佳置换算法&#xff08;OP…...

基于侏儒猫鼬优化的BP神经网络(分类应用) - 附代码

基于侏儒猫鼬优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于侏儒猫鼬优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.侏儒猫鼬优化BP神经网络3.1 BP神经网络参数设置3.2 侏儒猫鼬算法应用 4.测试结果…...

ios safari 正则兼容问题

背景: 系统是自己开发的采购管理系统; 最近升级系统之后客户反馈部分苹果手机现在在进入单据界面的时候报错, 内容显示不全; 安卓手机正常; 苹果首页是之前有使用过系统的才不行, 如果是之前没有使用过系统, 现在也是可以(后面查证这一点可能不是很准确, 跟是否等过过系统…...

Win10下基于VS2015编译SQLite3源码

一、下载SQLite SQLite SQLite Download Page 下载红框部分的3个文件 提示&#xff1a;这里有个 sglite-autoconf-3420000.tar.gz 是免编译版&#xff0c;想省事就下载这个&#xff0c;但我自己用这个老是编译不过 所以我这里不推荐这个了 二、配置SQLite 打开vs 2015或者其他…...

Linux 指令学习

Linux 指令学习 以此为记录&#xff0c;也方便自己日后查看回顾&#xff01; Linux命令基础格式 无论是什么命令&#xff0c;用于什么用途&#xff0c;在Linux中&#xff0c;命令有其通用的格式&#xff1a; command&#xff1a; 命令本身 options&#xff1a;[可选&#xf…...

前端渲染后端返回的HTML格式的数据

在日常开发中&#xff0c;经常有需要前端渲染后端返回页面的需求&#xff0c;对于不同数据结构&#xff0c;前端的渲染方式也不尽相同&#xff0c;本文旨在对各种情况进行总结。 后端返回纯html文件格式 数据包含html标签等元素&#xff0c;数据类型如下图&#xff1a; 前端通…...

身份证读卡器ubuntu虚拟机实现RK3399 Arm Linux开发板交叉编译libdonsee.so找不到libusb解决办法

昨天一个客户要在RK3399 Linux开发板上面使用身份证读卡器&#xff0c;由于没有客户的开发板&#xff0c;故只能用本机ubuntu虚拟机来交叉编译&#xff0c;用客户发过来的交叉编译工具&#xff0c;已经编译好libusb然后编译libdonsee.so的时候提示找不到libusb&#xff0c;报错…...

触想五代强固型工业一体机在近海船舶上的应用

1、行业发展背景 近海船舶的发展紧密关联着海上运输、渔业贸易、旅游开发、能源探测等多领域&#xff0c;带动区域经济、文化繁荣发展。 随着现代科学与信息技术在各行各业的作用增强&#xff0c;工业4.0带动的产业升级逐步渗透进船舶领域&#xff0c;在此背景下&#xff0c;船…...

Node-创建Web应用

题记 node创建web应用&#xff0c;以下是所有流程和代码 与php比较&#xff1a;使用 PHP 来编写后端的代码&#xff0c;需要 Apache 或者 Nginx 的 HTTP 服务器&#xff0c;并配上 mod_php5 模块和 php-cgi。 Node应用的组成 node应用由三部分组成&#xff1a; require 指令&a…...

Redis查找并删除key

redis安装在IP为x.x.x.x的服务器上 redis安装 第一步&#xff0c;安装编译工具及库文件。 命令&#xff1a;yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel 第二步&#xff0c;下载redis安装包。 命令&#xff1a;cd /usr/local/src wget ht…...

Spring Security认证架构介绍

在之前的Spring Security&#xff1a;总体架构中&#xff0c;我们讲到Spring Security整个架构是通过Bean容器和Servlet容器对过滤器的支持来实现的。我们将从过滤器出发介绍Spring Security的Servlet类型的认证架构。 1.AbstractAuthenticationProcessingFilter AbstractAut…...

提升代码重用性:模板设计模式在实际项目中的应用

在软件开发中&#xff0c;我们经常面临着相似的问题&#xff0c;需要使用相同的解决方法。当我们希望将这种通用的解决方法抽象出来&#xff0c;并在不同的情境中重复使用时&#xff0c;就可以使用设计模式中的模板模式&#xff08;Template Pattern&#xff09;。模板模式是一…...

11-k8s-service网络

文章目录 一、网络相关资源介绍二、开启ipvs三、nginx网络示例四、pod之间的访问示例五、service反向代理示例 一、网络相关资源介绍 Servcie介绍 Service是对一组提供相同功能的Pods的抽象&#xff0c;并为它们提供一个统一的入口。借助Service&#xff0c;应用可以方便的实现…...

MyBatisPlus(二十二)代码生成器

使用场景 使用代码生成器&#xff0c;根据数据库表&#xff0c;自动生成对应的 Entity&#xff0c;Mapper&#xff0c;Service&#xff0c;Controller 。 代码 依赖 两个依赖&#xff1a; 生成器依赖模板依赖 <dependency><groupId>com.baomidou</groupId&…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...