Android - 自动化埋点

字节跳动大规模实践埋点自动化测试框架设计 大数据时代,多数的web或app产品都会使用第三方或自己开发相应的数据系统,进行用户行为数据或其它信息数据的收集,在这个过程中,埋点是比较重要的一环。埋点收集的数据一般有以下作用: 驱动决策:ABtest、漏斗优化、用户增长、bug修复、精准营销、流失用户预警 驱动产品智能:智能推荐(千人千面)、场景化提示(私人助理)等 驱动安全:风险识别 01、埋点测试分类 埋点测试,首先要了解埋点的分类。 埋点主要分为:前端埋点、后端埋点 前端埋点:前端埋点可以理解为web端,app端等在前端触发相关规则时进. 阅读详情

原文:http://www.imwillsun.com/pages/2014/01/10/auto-monitor-on-android.html


当我们开发一款Android应用上线后,希望能收集一些用户操作的行为数据,比如用户在某个页面点击了多少次,在某个控件被点击了多少次,在某个页面停留了多少时间等。这些数据收集起来可以交给数据分析师,他们可以统计出应用的PV或UV;或者统计应用中哪些页面最受欢迎,哪些控件点击率最低,从而来改进应用。对于控件被点击多少次,一般做法是在控件点击事件中加入几行log代码,然后将此次的点击记录下来,最终发送到服务端,页面的点击也是类似,需要在页面生命周期的开始加入log代码。这种插入log代码记录操作行为的方式定义为埋点。但麻烦的是,如果业务逻辑复杂,页面众多,控件众多,那就要在许多地方插入这些log代码。这是一件多么重复的事情呀!

那有没有可能自动化去埋点呢?就是将界面的打开、关闭以及控件点击的log记录放到统一的地方去处理,而不用在许多业务逻辑中加入log代码。这块统一的监控代码需要做到如下的事情:

1.可以监控到界面打开或者关闭,并将这种操作记录到log中 
2.当界面上的有控件被点击的时候,可以监控到哪个界面哪个控件被点击了,并将这些操作信息记录到log中 
3.要能实现埋点的定制,即对需要埋点的控件或者界面才记录它们的操作log

下面分析一下自动化埋点的思路。

自动化埋点的思路

首先对Android的Activity和UI做个基本的了解,然后再提供一些自动化埋点的思路。

1.Activity的生命周期

学习Android,Activity的生命周期是必修课。Activity的生命周期分为onCreate,onStart,onResume,onPause,onStop和onDestroy,一个界面的展示和消失都会要经过这几个阶段,所以如果监控了Activity的生命周期,就可以监控一个界面的打开、关闭以及用户在界面上停留的时间。实现这种监控方式,可以通过创造一个界面基类,让所有业务界面去继承它,然后基类中重写所有Activity的生命周期方法,见如下代码。至于BaseActivity重写方法里做什么样的拦截处理,这个会在下面说到。

public BaseActivity extends Activity{
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //这里对Activity的生命周期进行拦截,其他的方法也是
    }
}
public BusinessActivity extends Activity{
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);   //一定要调用super的方法
        //这里写一些业务代码
        ...
    }
}

2.Android的UI布局

Activity中的UI布局是层层嵌套的,很类似HTML的布局。在一个Activity中,“根”view是PhoneWindow$DecorView,可通过this.getWindow().getDecorView()获取到这个对象。通过实例说明一下,在一个空白的Activity界面中添加一个Button按钮,下图是利用hierarchyviewer截到的UI布局图。

图中的DecorView类似于HTML中的<html>标签,里面嵌套的第一层Linearlayout类似于<body>标签。Linearlayout中有两个子view,都是FrameLayout布局,它们类似于<div>标签。第一个FrameLayout是应用的titlebar,TextView是titlebar上的文字;第二个FrameLayout中的内容就是Activity中的布局。可以看到最外层的采用RelativeLayout布局,里面有个Button按钮。 
先做下简单了解,下面会说到它跟自动化埋点的关系。

3.Android事件传递机制

Activity中的UI布局是层层嵌套的,如果点击一个界面上的控件,点击事件的传递是由父视图向子视图传递,然后再传到具体的控件中,这个跟HTML中的点击事件冒泡一样。我们简单看一下Android的事件传递机制是怎么实现的。

在View中关于事件响应的方法有两个:

public boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)

而ViewGroup除了这个方法还有一个方法:

public boolean onInterceptTouchEvent(MotionEvent event)

这些方法的返回值都是布尔型,返回的true或false决定了一个事件的响应能不能向下传递。我们来看一下这几个方法的作用。

  • dispatchTouchEvent方法用于事件的分发,在Activity界面中所有的点击事件都要经过这个方法的分发。返回true表示不分发事件,由当前的View来消费事件响应;返回false则继续往下分发,如果是ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截该事件。
  • onTouchEvent方法用于事件的处理,返回true表示消费处理当前事件,返回false则不处理,交给子控件进行继续分发。这个方法主要在普通控件中,比如Button。
  • onInterceptTouchEvent是ViewGroup中才有的方法,View中没有,它的作用是负责事件的拦截,返回true的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。这是ViewGroup特有的方法,因为ViewGroup中可能还有子View,而在Android中View中是不能再包含子View的。

除了上述的事件,Android提供了一个OnTouchListener的监听器,当事件传递到控件的时候,如果控件注册了这个监听器,则会执行监听器中的onTouch方法。同时,如果它返回true,则事件也是不继续向下传递了。

public boolean onTouch(View v, MotionEvent event)

上述的事件传递可以通过举一个例子说明,假设一个界面上有一个Button按钮,当我们touch down这个Button的时候,DOWN事件的传递如下:

Activity->dispatchTouchEvent       
Button->dispatchTouchEvent
Button->onTouch
Button->onTouchEvent

这里的每一步返回false,事件就不会向下传递。当我们touch up这个Button的时候,UP事件的传递如下:

Activity->dispatchTouchEvent       
Button->dispatchTouchEvent
Button->onTouch
Button->onTouchEvent    
Button->click

可以看到,一个Button的click事件要经过上面几个过程。如果要监听一个Button的click事件,有一种思路是我们可以创建一个基类BaseButton继承自Button,在回调OnClickListener的地方加入拦截代码。但是麻烦的是,点击控件不一定是Button,可能是其他TextView或者Layout之类的,Android中控件很多,我们要造很多控件基类,这样应用中充满的控件都必须是我们自己创建的控件,这样的设计是相当庞杂的。

那么我们考虑另外一种思路:让创建的BaseActivity基类重写Activity的dispatchTouchEvent方法,当touch button时,可以获取到按下(DOWN)和抬起(UP)时产生的MotionEvent对象。这个MotionEvent对象有两个方法,getRawX()和getRawY(),通过这两个方法我们可以获取到“点击位置”在界面中的坐标。同时,上文中提到,Activity的UI是层层嵌套的,通过“根”view可以层层遍历其下的子view以及所有子View上的控件,这些View和控件在屏幕中的坐标和宽高我们是可以获取到的。好了,这样就可以搜索所有的子View或者控件的布局区域是否包含“点击位置”,从而来判断哪个View或控件被点击。具体判断可以通过如下代码实现。

public boolean isInView(View view,MotionEvent event){
    int clickX = event.getRawX();   
    int clickY = event.getRawY();
    //如下的view表示Activity中的子View或者控件
    int[] location = new int[2];    
    view.getLocationOnScreen(location);  
    int x = location[0];
    int y = location[1];
    int width = view.getWidth();
    int height = view.getHeight();
    if (clickX < x || clickX > (x + width) || 
        clickY < y || clickY > (y + height)) {
        return true;  //这个条件成立,则判断这个view被点击了
    }
    return false;
}

自动化埋点的实现

综上我们可以整理一下自动化埋点的思路。对于自动化埋点第一个功能,可以通过创建基类BaseActivity重写Activity的所有的生命周期。对于自动化埋点的第二个功能,实现方式是,通过重写Activity的dispatchTouchEvent方法,点击事件发生时,通过MotionEvent对象获取点击位置坐标,然后遍历Activity界面中所有的View(控件也都是View),判断哪个View区域包含点击位置,从而判断哪个View被点击了。另外有个问题,当拦截到这些操作信息,如何将它放到一个统一的地方去处理呢?可以采用广播的方式,将相关数据发送出去,然后在一个BroadcastReceiver中统一处理埋点的log生成。看如下代码:

public BaseActivity extends Activity{
    //其他的Activity生命周期重写类似
    protected void onStart() {
        super.onStart();
        LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
        Intent intent = new Intent(ACTIVITY_START);
        intent.putExtra(ACTIVITY_START, event);
        broadcastManager.sendBroadcast(intent);
    }
    protected boolean dispatchTouchEvent(MotionEvent ev) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
            Intent intent = new Intent(VIEW_CLICK);
            intent.putExtra(VIEW_CLICK, event);
            broadcastManager.sendBroadcast(intent);
        }
    }
}

public class AutoMonitorReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if(action == VIEW_CLICK){
            MotionEvent event = intent.getParcelableExtra(VIEW_CLICK);
            //1.递归遍历Activity(就是Context)中的所有View,找出被点击的View
            View clickView = searchClickView(view, event);
            //2.生成log记录下来
            writeLog(); 
        }else if(action == ACTIVITY_START){
            //可以知道某个界面被打开了,然后记录此次操作行为
            writeLog();
        }
    }
    private View searchClickView(View view, MotionEvent event) {
        View clickView = null;
        if (isInView(view, event) && 
            view.getVisibility() == View.VISIBLE) {  //这里一定要判断View是可见的
            if (view instanceof ViewGroup) {    //遇到一些Layout之类的ViewGroup,继续遍历它下面的子View
                ViewGroup group = (ViewGroup) view;
                for (int i = group.getChildCount() - 1; i >= 0; i--) {
                    View chilView = group.getChildAt(i);
                    clickView = searchClickView(chilView, event);
                    if (clickView != null) {
                        return clickView;
                    }
                }
            }
            clickView = view;
        }   
        return clickView;
    }
}

又一个问题,代码中的writeLog方法到底要记录哪些数据作为log信息呢?log信息中最重要的是能让开发者看出来哪个界面被打开或者哪个控件被点击。对于界面,可以记录其类名;对于控件,一般没有确定的名称,那么可以记录下来这个控件在界面中的路径。比如上文中介绍Android UI布局的实例,如果要定位记录那个Button,则可以记录它所在界面的类名和Button的布局路径作为它的标识。那个Button的路径可以表示为DecorView>LinearLayout[0]>FrameLayout[1]>RelativeLayout[0]>Button[0],由于LinearLayout有多个子View,因此可以在子View中加入编号来区分。这样就解决了log信息的记录问题,log信息的格式大致要有如下几个字段:

monitor_type | ui_name | view_ui_path

比如是控件点击埋点log,则可以记录为

VIEW_CLICK | MainActivity | DecorView>LinearLayout[0]>FrameLayout[1]>RelativeLayout[0]>Button[0]

比如是MainActivity界面打开的埋点log,则可以记录为

ACTIVITY_START | MainActivity | NULL

这样我们分析这些日志信息,就可以统计出一个应用中各个页面被打开过多少次,某个界面的控件被点击过多少次。

对于自动化埋点的第三个功能,实现埋点的定制,这个比较好实现。如果我们需要对那些界面或者控件进行埋点,我们可以定制一个埋点列表。这个列表在应用启动的时候被下载到用户的手机上,然后AutoMonitorReceiver需要多做一点事,就是将广播发送过来的埋点信息与埋点列表进行比对,看是不是需要埋的点,如果是,就将其记录;如果不是,就不做处理。假设我们用json存储这个埋点列表,大致的结构如下:

{
    "version": "app_1.1.1",
    "view_id":"MainActivity": {
        "DecorView>LinearLayout[0]>FrameLayout[1]>RelativeLayout[0]>Button[0]":"button_0"
        "DecorView>LinearLayout[0]>FrameLayout[1]>RelativeLayout[0]>Button[1]":"button_1"
    }
}

当然这个埋点列表如何生成,这个需要开发者自己写代码去处理。

自动化埋点存在的问题和难点

本文提供的自动化埋点的思路是,通过拦截屏幕点击事件来搜索被点击的控件,然后将其界面类名和控件的UI路径记录下来作为log信息。将控件的UI路径和所在的界面类名作为一个控件的标识,有时候会出现一些问题,比如:

1.Android版本不同会造成控件的UI路径不同。比如Android2.2与Android4.1版本下,获取到上文中Button的UI路径分别为

//android2.2
DecorView>FrameLayout[1]>RelativeLayout[0]>Button[0]
//android4.1
DecorView>LinearLayout[0]>FrameLayout[1]>RelativeLayout[0]>Button[0]

这个问题可以通过将控件的UI路径缩短来解决,比如就只用FrameLayout[1]>RelativeLayout[0]>Button[0]路径来标识Button控件。

2.对一些隐藏控件、弹出窗口或者浮动窗口不好处理。比如,在上文中的Button同样位置存在另外一个Button,不过是隐藏的,有时出现,有时不出现。当一个Button被点击,单纯依靠DecorView>FrameLayout[1]>RelativeLayout[0]>Button[0]路径不能判断出是哪个Button被点击。解决这个问题,有时做一些特殊处理可以解决,比如扩展log的字段,多加入一些控件的信息,比如Button上的文字等。但是有时,开发应用的控件布局千变万化,一些控件确实不能通过UI路径进行唯一标识,这种就没法自动化埋点了。只能通过手动埋点来来补充了。

3.文中提到为了实现埋点的定制,需要开发者自己写代码生成一个埋点列表,这个也是比较麻烦的。要遍历一个应用中所有界面和界面中控件的UI路径,这个比较容易,但是取出自己想要埋点的控件UI路径,这个可能需要人工去查看比对。另外,一些大型应用开发的时候,界面随时发生着变化,一些控件的布局在随时发生变化。每次发布应用的时候,都需要扫描一下应用控件信息,以及重新找一下埋点控件的UI路径,这个是相当麻烦的。如何实现这部分的自动化,也是一个难题。

参考文章

InfoQ: Android事件传递机制


android控件自动化埋点统计 android控件自动化埋点统计 想到应用统计,平时我们使用的一般都是第三方的,比如百度统计,友盟统计,这几天公司要做自己的统计,于是乎也找了一些自动化埋点的博文学习使用。最后会给出参考链接,非常感谢。 现有的几种埋点技术的实现原理和优劣分析  1.代码埋点:将收集数据的代码直接写在需要的地方,当用户点击某个控件或者打开某个页面时调用到该部分代码完成数据的收集。   优势:准确性高,收 阅读详情

相关推荐

ASM的基础使用 Android 自动化埋点方案原理剖析

Android 自动化埋点方案原理

菜鸟博客 2820

埋点自动化测试框架设计

大数据时代,多数的web或app产品都会使用第三方或自己开发相应的数据系统,进行用户行为数据或其它信息数据的收集,在这个过程中,埋点是比较重要的一环。埋点收集的数据一般有以下作用:

人生不怕起点低,就怕没追求 1129

埋点治理&埋点回归&实时埋点自动化&离线数据监控

1. 埋点相关文档: 埋点涉及到的各种平台 UT平台:抓取实时埋点日志 正则平台:埋点case正则表达式 FBI监控平台:关注埋点监控日报 BI埋点数据监控平台:大盘数据 OneData报警平台:但暂不支持正则报警,待RD完善 2. 搜索埋点测试方法 背景 由于搜索埋点数据过于老化,导致统计方面的一些工作的不方便。经过产品评估后决定需要重构部分埋点字段的参数,所以搜索的iO...

疯批美人 7748

安卓日志埋点

import android.app.Activity; import android.content.Context; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; /** * 异常监控 * 使用: * 1.BaseActivity里重写该方法 * * @..

xiaoerbuyu1233的博客 297

Android自动化埋点(二) - JVM基本操作指令

JVM操作指令是字节码插桩必须要掌握的知识点,后面我们操作字节码,几乎每一行代码都离不开我们对操作指令的运用。

qq_15328623的博客 360

Android自动化埋点(三) - JVM对象操作指令

实际代码插桩过程中,很少会纯编写字节码文件,会造成代码篇幅很大,并且阅读性不好,不利于后期维护。采用的方式大多数通过插入字节码,对外部类中的方法进行调用。

qq_15328623的博客 252

android埋点设计,老李分享:Android -自动化埋点 1

老李分享:Android -自动化埋点当我们开发一款Android应用上线后,希望能收集一些用户操作的行为数据,比如用户在某个页面点击了多少次,在某个控件被点击了多少次,在某个页面停 留了多少时间等。这些数据收集起来可以交给数据分析师,他们可以统计出应用的PV或UV;或者统计应用中哪些页面最受欢迎,哪些控件点击率最低,从而来改 进应用。对于控件被点击多少次,一般做法是在控件点击事件中加入几行log...

weixin_29195217的博客 730

Android自动化埋点(五) - 最终实现

ASM是一个操作Java字节码的类库。 通过 ASM 修改字节码是目前 Android 自动化埋点所使用的主流技术, 我们不会去深究 ASM 的API,而是通过一个简单的例子,去了解 Android 代码插桩的一个基本实现。

qq_15328623的博客 1170

Android 自动化埋点(无痕埋点)代码插桩 Demo

Android 自动化埋点(无痕埋点)代码插桩 Demo 去发现同类优质开源项目:https://gitcode.com/ 本仓库包含了一个关于Android自动化埋点(又称无痕埋点)或字节码插桩技术的代码示例。自动化埋点是一种在应用运行时自动收集用户行为数据的手段,而无需手动编写大量的埋点代码。 仓库内容 一个Android项目示例,展示如何实现基础的Java字节码插桩。 文章简介 本系列文...

gitblog_06785的博客 448

微型纵向加密在新能源场站中的实战部署与运维避坑指南

本文详细解析了微型纵向加密在新能源场站中的实战部署与运维技巧。通过国密算法SM4实现数据加密,确保新能源场站通信安全,同时提供非侵入式部署方案和运维避坑指南,帮助提升网络稳定性和运维效率。

weixin_30505225的博客 596

立创电赛C题:基于STM32的三端口DC-DC变换器设计与MPPT算法实现

本文详细解析了2021年立创电赛C题——基于STM32的三端口DC-DC变换器设计。文章从题目要求出发,系统阐述了采用双DC-DC电路(分别负责MPPT追踪与稳压)的硬件架构,并重点讲解了以STM32为核心、结合PID控制与扰动观察法(MPPT算法)的软件实现方案,为备赛者提供了完整的软硬件设计思路与调试经验。

weixin_42588877的博客 224

Android-自动化埋点

原文:http://www.imwillsun.com/pages/2014/01/10/auto-monitor-on-android.html当我们开发一款Android应用上线后,希望能收集一些用户操作的行为数据,比如用户在某个页面点击了多少次,在某个控件被点击了多少次,在某个页面停留了多少时间等。这些数据收集起来可以交给数据分析师,他们可以统计出应用的PV或UV;或者统计应用中哪些页面最受欢

Android小酌 2714

龙迅LT9611UXC芯片简介:Dual-Port MIPI DSI/CSI to HDMI2.0 with Audio

龙迅半导体推出的LT9611UXC是一款高性能MIPI转HDMI2.0转换器,支持DSI/CSI接口转换,兼容多种视频格式(RGB/YCbCr),最高支持4K@60Hz输出。该芯片集成音频处理(I2S/SPDIF)、色彩空间转换和3D功能,适用于机顶盒、电视盒子等消费电子及车载设备。提供工业级(-40℃~+85℃)和车规级(AEC-Q100认证)版本,采用QFN64封装。

MB16698594834的博客 1334

Android应用--自动化埋点

http://blog.youkuaiyun.com/way_ping_li/article/details/7927273  http://blog.youkuaiyun.com/gykimo/article/details/24772853 http://ask.youkuaiyun.com/questions/10729 dasu

stayfish的专栏 2763

别让运放自激振荡!手把手教你用波特图分析反相放大电路的稳定性(附LTspice仿真)

本文详细解析了运算放大器在反相放大电路中的稳定性问题,通过波特图分析和LTspice仿真,揭示了自激振荡的成因及解决方案。文章从故障现象识别到数学工具应用,再到实战仿真和工程优化,提供了一套完整的稳定性分析工具链,帮助工程师有效避免运放自激振荡问题。

weixin_31682031的博客 303

深入解析Android Qcom Camera HAL3架构与Camx线程模块

本文深入解析了Android Qcom Camera HAL3架构与Camx线程模块的核心原理。文章以高通芯片平台为例,剖析了从按下快门到生成照片的完整Camera流程分析,重点阐述了Camx框架中线程池、消息队列及Fence同步机制如何协同工作,以实现高效、稳定的多线程并发图像处理,为相机性能优化提供理论基础。

weixin_29184075的博客 220

Android自动化埋点无痕埋点代码插桩Demo:为移动应用注入智能数据收集能力

Android自动化埋点无痕埋点代码插桩Demo:为移动应用注入智能数据收集能力 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 Android自动化埋点(无痕埋点)代码插桩Demo,是一个展示如何通过字节码插桩技术实现自动化埋点的Android项目示例。该技术能够在不修改源代码的情况下,自动收集用户的行为数据,对于提高应用的用户体验和数据分析效率具有显著优势。 项目技...

gitblog_06717的博客 1606

免ROOT、不刷机、不依赖Xposed实现Android改机的思路

最近在一个项目中需要模拟多种Android设备的环境。无奈市面上的大部分改机工具,要么需要ROOT权限,要么依赖Xposed,甚至还得重启设备。为了实现更灵活、更干净的改机方式,我开始了漫长的技术探索,最终找到了免ROOT、不刷机、拒绝Xposed的实现路径。Android_IDIMEI手机序列号手机型号、品牌、CPU型号等硬件信息GPS位置、Wi-Fi参数、通话记录、短信等软硬件数据这些信息通常用于标识设备唯一性,而改机就是对这些标识数据进行模拟或篡改。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 2667

Android 自动化埋点:基于AspectJ的沪江SDK的使用整理

说明:此文章是基于《AOP AspectJ 字节码 示例 Hugo MD》所做的整理,该博主写得很好,但是本人刚上手时,觉得某些点如果有注释讲解的话,对于刚上手的小白友好度更高,所以就厚颜无耻的按照自己的使用理解整理了此文章,基本都是直接搬的代码,见谅见谅哈 ~ 一、引入SDK 就如该博主所说,可以直接使用 AspectJ 的官方库集成配置,但是官方配置对于 Android 开发来说,有以下问题:...

zeqiao的博客 2440

【AI 智能体】Windows 环境 Hermes Agent(爱马仕)安装详细过程

Windows 环境 Hermes Agent(爱马仕)安装详细过程

congge_study的博客 1828

nRF52832——大量数据传输时导致蓝牙断开连接,且无法被搜索到的解决方案(广播参数的设置、程序设计方法)

有时蓝牙通信单次发送数据量较大,且连续发送多次的时候,你会发现蓝牙就会出现异常,可能运行30min,40min,或者1h后,蓝牙就不能传输数据了,且无法被搜索到,用主机扫描蓝牙时可能会提示类似这样的DEBUG信息:bta_gattc_mark_bg_conn unable to find the bg connection mask for bd_addr=xx:xx:xx:xx:xx:xx。

数字世界 万物互联 2004

android应用中自动化埋点的实现,Android 自动化埋点方案

一、事件实现原理:① View设置AccessibilityDelegate②而当View 产生了click,long_click 等事件的时候.会在响应原有的Listener方法③原有的Listener方法响应结束之后,然后在sendAccessibilityEvent方法中转发消息到AccessibilityDelegate④在AccessibilityDelegate的sendAccessi...

weixin_30844301的博客 487

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Android自动化埋点的实践

前几天在应用里加上了按钮点击的事件自动埋点功能,这个功能的实现在面试中问过很多次,得到的答案都不尽如人意,归根到底是没有理解“自动”这个需求,自己也思考过一些方案,但是一直没有一个比较靠谱的实现方式,直到看了这篇文章,才豁然开朗。 基本的思路是这样的:

fkaking的专栏 9818

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

老李分享:Android -自动化埋点 1

老李分享:Android -自动化埋点 当我们开发一款Android应用上线后,希望能收集一些用户操作的行为数据,比如用户在某个页面点击了多少次,在某个控件被点击了多少次,在某个页面停 留了多少时间等。这些数据收集起来可以交给数据分析师,他们可以统计出应用的PV或UV;或者统计应用中哪些页面最受欢迎,哪些控件点击率最低,从而来改 进应用。对于控件被点击多少次,一般做法是在控件点击事...

weixin_30364147的博客 108

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

上一篇: Innovation - Face++ - 当人脸识别遇上互联网
下一篇: C# - .net framework和CLR各版本之间的关系
G机器猫
博客等级 码龄16年 106粉丝 74原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值