除了上述的事件,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的更多相关文章

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

    老李分享:Android -自动化埋点   当我们开发一款Android应用上线后,希望能收集一些用户操作的行为数据,比如用户在某个页面点击了多少次,在某个控件被点击了多少次,在某个页面停 留了多少时 ...

  2. 老李分享:Android -自动化埋点 3

    又一个问题,代码中的writeLog方法到底要记录哪些数据作为log信息呢?log信息中最重要的是能让开发者看出来哪个界面被打开或者哪个控件被点 击.对于界面,可以记录其类名:对于控件,一般没有确定的 ...

  3. 老李分享:android app自动化测试工具合集

    老李分享:android app自动化测试工具合集   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨 ...

  4. 老李分享:Android性能优化之内存泄漏1

    老李分享:Android性能优化之内存泄漏   前言 对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我 ...

  5. 老李分享:接电话扩展之uiautomator 1

    老李分享:接电话扩展之uiautomator   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq ...

  6. MTFlexbox自动化埋点探索

    1. 背景 跨平台动态化技术是目前移动互联网领域的重点关注方向,它既能节约人力,又能实现业务快速上线的需求.经过十年的发展,美团App已经变成了一个承载众多业务的超级平台,众多的业务方对业务形态的快速 ...

  7. 老李分享:接口测试之jmeter

    老李分享:接口测试之jmeter   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.移动端自动化测试很多人把他仅仅理解成appu ...

  8. POPTEST老李分享修改dns ip的vbs代码

    POPTEST老李分享修改dns ip的vbs代码   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨 ...

  9. 老李分享:robotium3.6与4.0 later 的区别 1

    老李分享:robotium3.6与4.0 later 的区别   因为下载的直接是最新版本的robotium4.1版,这次碰到gridView问题时,发现网上有getCurrentListViews( ...

随机推荐

  1. HTTP协议详解【转】

    当今web程序的开发技术真是百家争鸣,ASP.NET, PHP, JSP,Perl, AJAX 等等. 无论Web技术在未来如何发展,理解Web程序之间通信的基本协议相当重要, 因为它让我们理解了We ...

  2. [Usaco2014 Open]Gold Fair Photography(hash)

    最近做了usaco2014 open的金组,果然美帝的题还是没有太简单啊QAQ,被每年的月赛骗了QAQ 不过话说官方题解真心棒(虽然英文的啃得好艰难,我英语渣你们别鄙视我= =),标程超级优美QAQ ...

  3. WP8.1开发对图片进行裁剪(截取)一部分

    对于这个内容,我是在学习插入图片时遇到的问题,在Windows应用中可以直接用Image类和Bitmap直接实现裁剪功能, 在wp上就不行了,后来在MSDN论坛上找到了相关方法及示例,而示例太复杂了, ...

  4. BI数据分析中KPI,KGI,CSF概念

    1. 行为产生数据 先来谈一谈,自己对数据基础概念的思考.我认为首先要建立的核心观点是:行为产生数据. 翻译一下这个核心观点.意思就是,当我们在思考或描述数据相关需求的时候,必然要包含这样的语素:&q ...

  5. C#开发step步骤条控件

    现在很多的javascript控件,非常的不错,其中step就是一个,如下图所示: 那么如何用C#来实现一个step控件呢? 先定义一个StepEntity类来存储步骤条节点的信息: public c ...

  6. 更改Debian Linux里面的EDT时区为CST时区

    Debian按默认安装,设置的是EDT时区.这样跟我们的系统就都对不上,因此得 改回CST. 只需要两步即可: 使用vi编辑/etc/timezone,把timezone文件的内容更改为:Asia/S ...

  7. Triangle Problems

    Triangle Problem songxiuhuan 宋修寰 Import the Junit and eclemma Choose the project and right click, ch ...

  8. ACM 整数划分(四)

    整数划分(四) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 暑假来了,hrdv 又要留学校在参加ACM集训了,集训的生活非常Happy(ps:你懂得),可是他最近 ...

  9. 1651: [Usaco2006 Feb]Stall Reservations 专用牛棚

    1651: [Usaco2006 Feb]Stall Reservations 专用牛棚 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 566  Sol ...

  10. Struts 基本概念,优点及不同版本之间的关系

    strutx 1.x struts 是 apache 基金会的一个开源项目. struts 是一套实现 MVC的框架. MVC = 程序分层设计的思想 = Model(数据访问层1) / View(视 ...