如何设计一个伪无埋点的框架?

news/2024/11/15 19:26:57/文章来源:https://www.cnblogs.com/WoodJim/p/18429826

本文同步发布于公众号:移动开发那些事如何设计一个伪无埋点的框架

在前面的文章:Android无埋点技术概览 中提到传统的无埋点有几大缺点:

  • 埋点字段有限,没有办法携带精确的业务字段;
  • 数据量太大,后台存储压力很大;
  • View的唯一ID会随着页面的变化而变化,多个版本的数据需要在后台进行数据映射;

这几个缺点也是很多业务在进行技术方案选型时,不敢去选择无埋点的原因。那么有没有办法做到既可以利用无埋点的特性,并且又能满足业务的数据分析需求呢?
要能满足业务的数据分析需求,又能利用无埋点的特性,这意味着需要满足以下条件:

  • 上报能携带业务字段;
  • 上报可以按需选择;
  • 上报时机由框架控制;

简化成一句话就是:业务控制上报内容与类型,框架决定上报时机,这也是本文要讲述的“伪”无埋点框架的核心;
如无特殊说明,文章里说的无埋点就是指代"伪"无埋点。

1 伪无埋点

在传统的代码埋点的方案,一般是业务同学在需要上报的时机,把要上报的具体的参数调用数据上报SDK的接口进行上报,如,当某个view被点击时,上报点击事件:

// 业务在调用完这个上报接口后,由数据上报SDK把对应的数据上报到后台;
Report.report("event_click", {key:value});

而伪无埋点框架也是基于传统的代码埋点方案演变而来:由业务把某个View要上报的业务参数和对应的业务标识设置给对应的View,框架层负责在合适的时机去调用数据上报SDK的接口去进行上报,使用的伪代码为:

//步骤1 某个要上报的view,设置对应的上报参数
viewA.setReportParsms({key:value}});// 步骤2,框架回调上报SDK接口进行上报Report.report("event_name", {key:value});

那么这里的无埋点框架需要解决两个主要问题:

  • 上报view的检测: 怎样检测到某个View需要做上报;
  • 上报参数的设置: 框架可以怎样获取到View要上报的业务参数;

2 上报view的检测

要想检测到哪些View需要做上报,需要有一个通用的机制来获取到所有的要检测到的View,这里最常规的方案就是通过实现大量的自定义View来实现,如自定义的ViewGroup,自定义Text等。只要需要做这些检测的View都使用这些自定义的View来实现,但这个常规的实现方案的成本很大:

  • 框架的开发成本大,需要自定义大量的View,只要业务有用到的,都需要去自定义;
  • 业务的接入成本过高,需要将现在使用的组件替换为埋点框架的;

那这里有没有其他相对低成本的方案呢?那肯定是有,接下来我们来看一个比常规方案好一点的方案

2.1 进阶方案

大家都知道,Android的页面是有生命周期方法的,不管是Activity还是Fragment在进入前台时,系统都会回调一些生命周期的方法,如onResume,onPause。那么我们是不是可以在系统回调这些方法时,对页面进行一个检测,获取到整个ViewTree呢?只要获取到了ViewTree ,那么我们就可以通过某个标识来判断到哪些是需要做上报的View后续只需要去判断这些View的状态就可以了。这也是某埋点框架采用的方案。但这个方案会有个缺点:没有办法覆盖到所有的view变化的时机 像手动通过addViewremoveView去更新ViewTree的时候,这个方案就没有办法检测到。因此这个方案的时机还需要检测业务同学在某个时机,手动去调用检测的接口,来触发检测。这个进阶方案,也会存在几个缺点:

  • 检测时机不可控,由框架和业务共同控制;
  • 业务的接入成本有点高:
    • 需要在页面的某些生命周期去调用框架的检测方法;
    • 手动操作viewtree时,需要调用框架的检测方法;
    • 存在漏报的可能性(某个场景下,业务漏调用了检测方法);

这个进阶的方案虽然框架的开发成本和接入成本比常规方案有降低,但整体的成本还是比较大的,有没有更完美的方案呢?一个比较完美的方案应该是

  • 能监测到所有ViewTree变化的时机;
  • 比较低成本的开发成本和接入成本;

接下来我们继续去探索一下完美的终极方案是怎样的?

2.2 终极方案

如果我们能想监测到所有ViewTree的变化时机,这里只能是自定义View。有同学看到这,肯定会想“就这?,前面已经说过自定义View的成本很高,现在又说自定义View,这不是有点自相矛盾吗?“。别急,我们一步步来拆解出可以怎样做到低成本的自定义View的终极方案。

这里要做到低成本,关键在于自定义View的个数尽可能要少,并且业务最好能无感知接入。所以这里的问题变成:怎样找到这些少量的View。这里我们就只能从Android的页面Activity入手了。不管我们使用了什么开发框架,应用的页面一定是Activity,而Activity的根view都是一个FrameLayout(这里我们可以去查看Android的源码去确认一下,其实从性能优化的减小布局层次的介绍中(如果布局layout.xml中的根viewFrameLayout的话,推荐使用merge标签)也能看出来了)。这里是不是可以自定义一个FrameLayout就可以解决了。到这里其实答案就已经出来了。

我们通过自定义FrameLayout来监听各种会引起view变化的事件,如

  • void dispatchWindowVisibilityChanged(int visibility)
  • void onLayout(boolean changed, int left, int top, int right, int bottom)

有了这个根view,我们就能获取到当前页面的所有view,然后通过标识就能找到要上报的所有view了。但现在问题又来了,怎样可以把业务的view 替换为这个自定义的view呢?最低成本的方法其实就是运行时替换,在监听到ActivityonResume方法被调用时,动态把根view替换掉就可以了。
综上,这里的终极方案为:

  • 自定义FrameLayout,开发成本低(只需要一个自定义view
  • 运行时替换,业务接入成本低 (业务不用关心检测时机,只关注业务就可以)

通过这个方案,我们就能检测到所有的view,并可以根据view的标识来做一些上报的处理,但我们还需要解决怎样标识一个view 的问题?

3 上报参数的设置

要想把上报参数和对应的view进行绑定,那么view就需要有字段属性来存储我们设置的参数。一听到额外的字段属性,最常见的两种方案:

  • 通过继承类,来增加属性;
  • 通过扩展类,来增加属性;

继承类的方式也就是自定义View的方式,这里的改造成本很大; 而扩展类的方式由于Android开发使用的语言没有这一类的使用方式。因此最常见的这两种方案不适合这里,我们只能从源码出发,寻找有没有现在的字段可以使用;查看了一翻View的源码后,发现有这么一个方法setTag

public class View {/*** Sets a tag associated with this view and a key. A tag can be used* to mark a view in its hierarchy and does not have to be unique within* the hierarchy. Tags can also be used to store data within a view* without resorting to another data structure.** The specified key should be an id declared in the resources of the* application to ensure it is unique (see the <a* href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>).* Keys identified as belonging to* the Android framework or not associated with any package will cause* an {@link IllegalArgumentException} to be thrown.** @param key The key identifying the tag* @param tag An Object to tag the view with** @throws IllegalArgumentException If they specified key is not valid** @see #setTag(Object)* @see #getTag(int)*/public void setTag(int key, final Object tag) {// If the package id is 0x00 or 0x01, it's either an undefined package// or a framework idif ((key >>> 24) < 2) {throw new IllegalArgumentException("The key must be an application-specific "+ "resource id.");}setKeyedTag(key, tag);}

从这个方法的注释上可以看到这个方法是可以满足我们的需求,只是在使用的过程中需要注意这个key一定要是Android的资源id,再细看源码后,发现还有个需要注意的地方:tagView 内部是通过SparseArray 来存储的,而这个数据结构是非线程安全的,因此在调用setTag方法一定要在主线程里去调用;

3.1 key值的定义

使用setTag方法时的key一定要是资源id,只需要在res目录下的values下新建一个ids.xml的文件,里面的内容示例如下

<resources><item name="VIEW_PARAMS_KEY" type="id" /></resources>

在使用时,就使用R.id.VIEW_PARAMS_KEY 来获取到具体的值就可以了;

4 总结

本文主要围绕Android中设计一个伪无埋点框架需要解决的两个问题展开:

  • 上报view的检测: 核心是通过自定义FrameLayout,并在运行时替换来解决;
  • 上报参数的设置: 核心是通过设置ViewsetTag方法来进行设置和获取;

通过解决这两个关键问题,大家也就可以快速搭建起一个伪无埋点的框架了;在后面的文章里,会讲述如何基于这个框架,去搭建一个有效曝光的框架;

公众号:

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

吴恩达机器学习课程 笔记4 分类 逻辑回归

逻辑回归 机器学习中的逻辑回归(Logistic Regression)是一种广泛使用的分类算法,尽管它的名字中包含“回归”这个词,但实际上它主要用于解决分类问题,特别是二分类问题。逻辑回归模型可以用来预测某一类事件发生的概率,例如预测用户是否会点击广告、病人是否患有某种疾病…

设计模式之中介模式(三分钟学会一个设计模式)

中介模式(Mediator)又称之为调停模式。mediator [ˈmiːdieɪtə(r)] n. 调停者;斡旋者;解决纷争的人(或机构); 本意就是解决纠纷的中间人它是面向对象六大原则中最少知道原则的一个典型应用。(关于面向对象六大原则,可看前文:https://www.cnblogs.com/jilodream/p/535351…

Large Vision Model

LVM https://yutongbai.com/lvm.html https://zhuanlan.zhihu.com/p/671423679Large Vision Model(简称LVM)是一种纯粹基于视觉数据进行训练和推理的大型模型,其特点在于无需涉及任何自然语言输入或输出。该模型的提出源自一篇由UC Berkeley的三位计算机视觉专家联合撰写的论…

2024 天池云原生编程挑战赛决赛名单出炉,冠军来自中山大学、昆仑数智战队

9 月 20 日,2024 天池云原生编程挑战赛决赛答辩完美落幕,12 支进入决赛的团队用精彩的答辩,为历时 3 个月的大赛画下了圆满的句号。其中,来自中山大学的陈泓仰以及来自昆仑数智的冉旭欣、沈鑫糠、武鹏鹏,以出色的方案、创新的优化思路、过硬的技术实力分获赛道一和赛道二的…

1panle搭建的maxkb增加本地向量模型

首先下载模型,比如m3e-large,并上传到/opt/maxkb/model/local_embedding/ 目录,没有就创建 目录如下:然后修改1panel的容器信息,点击右边的编辑:在下方的挂在目录处点击添加:在两个框都输入: /opt/maxkb/model/local_embedding 然后,确认保存,再重启容器 重启成功后…

WinForm右键菜单的快键键设置

原文链接:https://blog.csdn.net/zhourongxiang1/article/details/138176092 Form中有一个富文本框控件,在里面右键鼠标,弹出下拉菜单。快捷键的效果则是按下alt+p,触发按下属性事件。 1.从工具箱添加RichTextBox2.然后添加ContextMenuStrip 3.选择RichTextBox的ContextMenu…

信息学奥赛复赛复习02-CSP-J2019-02-结构体、无构造函数、有构造函数、初始化列表构造、集合、数组存在性判断

PDF文档公众号回复关键字:202409241 2019 CSP-J 题目2 公交换乘 [题目描述] 著名旅游城市 B 市为了鼓励大家采用公共交通方式出行,推出了一种地铁换乘公交车的优惠方案 在搭乘一次地铁后可以获得一张优惠票,有效期为 45 分钟,在有效期内可以消耗这张优惠票,免费搭乘一次票价…

重磅!阿里云可观测产品家族全新升级,AI +数据双驱动,打造全栈可观测体系

近日,阿里云可观测产品家族正式发布云监控 2.0,隶属产品日志服务 SLS、云监控 CMS、应用实时监控服务 ARMS 迎来重磅升级。借助全新升级的一站式全景接入、统一观测图谱以及 AI 增强的跨域智能洞察能力。引言: 近日,阿里云可观测产品家族正式发布云监控 2.0,隶属产品日志服…

期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟

在 AI 程序员的帮助下,一个几乎没有专业编程经验的初中生,在人头攒动的展台上从零开始,两分钟就做出了一个倒计时网页。在 AI 程序员的帮助下,一个几乎没有专业编程经验的初中生,在人头攒动的展台上从零开始,两分钟就做出了一个倒计时网页。 他需要做的,只是输入包含几句…

Serverless + AI 让应用开发更简单,加速应用智能化

2024 云栖大会开幕,在大会第一天,阿里云正式发布全新产品——云应用开发平台 CAP。CAP 拥有丰富的场景化应用模板,可以极速体验,并且具备更低的成本优势以及灵活组装等特点,成为广大开发者与企业必备的一站式应用开发平台,让应用开发更简单。阿里云云原生应用平台负责人 …

调用微信、支付宝支付逻辑

1.获取sku信息 通过参数app_id: "**" decision_token: "" platform: "web" product_type: "vip"获取支付的种类和 product_id 通过参数{product_id: "302048", pay_channel: "alipay_native", price: 29000, pri…