老李分享:Android -自动化埋点 2
除了上述的事件,Android提供了一个OnTouchListener的监听器,当事件传递到控件的时候,如果控件注册了这个监听器,则会执行监听器中的onTouch方法。同时,如果它返回true,则事件也是不继续向下传递了。
public boolean onTouch(View v, MotionEvent event)
上述的事件传递可以通过举一个例子说明,假设一个界面上有一个Button按钮,当我们touch down这个Button的时候,DOWN事件的传递如下:
Activity->dispatchTouchEvent Button->dispatchTouchEventButton->onTouchButton->onTouchEvent
这里的每一步返回false,事件就不会向下传递。当我们touch up这个Button的时候,UP事件的传递如下:
Activity->dispatchTouchEvent Button->dispatchTouchEventButton->onTouchButton->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;
}}
老李分享:Android -自动化埋点 2的更多相关文章
- 老李分享:Android -自动化埋点 1
老李分享:Android -自动化埋点 当我们开发一款Android应用上线后,希望能收集一些用户操作的行为数据,比如用户在某个页面点击了多少次,在某个控件被点击了多少次,在某个页面停 留了多少时 ...
- 老李分享:Android -自动化埋点 3
又一个问题,代码中的writeLog方法到底要记录哪些数据作为log信息呢?log信息中最重要的是能让开发者看出来哪个界面被打开或者哪个控件被点 击.对于界面,可以记录其类名:对于控件,一般没有确定的 ...
- 老李分享:android app自动化测试工具合集
老李分享:android app自动化测试工具合集 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨 ...
- 老李分享:Android性能优化之内存泄漏1
老李分享:Android性能优化之内存泄漏 前言 对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我 ...
- 老李分享:接电话扩展之uiautomator 1
老李分享:接电话扩展之uiautomator poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq ...
- MTFlexbox自动化埋点探索
1. 背景 跨平台动态化技术是目前移动互联网领域的重点关注方向,它既能节约人力,又能实现业务快速上线的需求.经过十年的发展,美团App已经变成了一个承载众多业务的超级平台,众多的业务方对业务形态的快速 ...
- 老李分享:接口测试之jmeter
老李分享:接口测试之jmeter poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.移动端自动化测试很多人把他仅仅理解成appu ...
- POPTEST老李分享修改dns ip的vbs代码
POPTEST老李分享修改dns ip的vbs代码 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨 ...
- 老李分享:robotium3.6与4.0 later 的区别 1
老李分享:robotium3.6与4.0 later 的区别 因为下载的直接是最新版本的robotium4.1版,这次碰到gridView问题时,发现网上有getCurrentListViews( ...
随机推荐
- web移动端Fixed在Input获取焦点时ios下产生的BUG及处理
1.现象 可以看到下面两张图,图1搜索框为fixed固定在顶部,滚动没有任何问题. 图2当光标进入搜索框时,ios自作聪明的把光标定位到中间,并且fixed属性被自动修改成了absolute.此时注意 ...
- 360随身wifi无法使用临时解决方案大全
360随身wifi在绝大多数情况下都是可以正常使用的,但在极少数系统或网络环境下可能会出现异常,如系统服务缺失.公司网络限制.少数校园网客户端限制等等: 360攻城师正在积极努力解决 ...
- linux下载时提示请尝试移除磁盘中不需要的文件并重试,或者保存到其他位置
因为我是用虚拟机装的linux,所以当时就分配了20G硬盘,下载了几个应用后再下载就提示我这个了.一开始我还以为是因为下载链接的问题,后来才知道原来是因为/tmp的满了. 然后我输入以下连个命令就能正 ...
- 用Ajax实现自动刷新news功能
这是Ajax应用的一个小实例:在页面中自动刷新功能,比如整个新闻页面中某一个小版块的内容,无需刷新整个页面就可以自动更新: 1.首先创建简单的页面元素: <body> <input ...
- 2017-2-21 C#基础 if条件语句,作用域
今天学了if 条件语句和作用域.作用域可以用一句话来概括:儿子可以用爹的所有东西,爹不可以用儿子的任何东西.If条件语句我用几个练习题来解释. 1."请输入年份:" 判断是否是闰年 ...
- 深入探讨 CSS 特性检测 @supports 与 Modernizr
什么是 CSS 特性检测?我们知道,前端技术日新月异的今天,各种新技术新属性层出不穷.在 CSS 层面亦不例外. 一些新属性能极大提升用户体验以及减少工程师的工作量,并且在当下的前端氛围下: 很多实验 ...
- asp.net中listview下嵌套gridview
最近在上软件工程实践课程,想做一个类似于QQ空间或者朋友圈一样的效果.即显示所有好友发送的动态以及动态下回复的信息. 自己YY了一种方法,一开始以为不能达到效果,研究了2个小时终于实现了,感觉效果还是 ...
- 每天一个Linux命令(11)--nl命令
nl命令在Linux系统中用来计算文件中行号.nl可以将输出的文件内容自动的加上行号,其默认的结果与cat -n 有点不太一样,nl可以将行号做比较多的显示设计,包括位数与是否自动不起0等等的功能. ...
- 深入简出的nginx
深入简出的nginx hosts的简单介绍 nginx的简单介绍 hosts介绍 谈到nginx我们不得不说hosts hosts的存放在C:\Windows\System32\drivers\etc ...
- 简单分析beyond作曲
本人绝对是业余的哈 业余到什么水平呢?正在练习爬格子,还是一个星期练几次那种 先说下<海阔天空> 6,5,4,3 1,2,3,4 简单是简单得不得了,声从低到高,然后再从高到低,产生一种回 ...