zoukankan      html  css  js  c++  java
  • 老李分享: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;
        }}
  • 相关阅读:
    HUE配置HBase
    HUE配置HIVE
    HUE配置hadoop
    HUE的安装
    CM (Cloudera Manager) 的安装,便于CDH的离线部署
    MapReduce -- 最短路径
    Mapreduce -- PageRank
    CentOS 建立本地yum源服务器
    js移动设备手机跳转地址代码
    离线存储
  • 原文地址:https://www.cnblogs.com/poptest/p/5113676.html
Copyright © 2011-2022 走看看