Android埋点技术深入探究
上一篇文章提到的无埋点技术在实际应用中有以下几个问题需要处理。
大纲:
【1】控件的唯一标识问题怎么处理。
【2】当控件处于可滑动的组件内或者整个界面就是一个可滑动的View中时位置如何确定。
【3】Fragment中如何得到触摸点的坐标。
【4】Activity界面留存时间。
第一个问题:控件的唯一标识问题,上一篇文章也是参考了其他的博客,说用控件的路径来标识。这种方式先不说获取到正确的路径就是一件比较难处理的事情,而且服务器端制定埋点位置时需要考虑不同版本的路径不一样,修改了布局文件后路径就需要更新。同时考虑到95%以上需要埋点的控件都是设置了id的,不会因为埋点而故意加id,所以用控件的id做唯一标识。
第二个问题:因为之前使用了View的getHitRect()方法获取view的位置坐标,当滑动后坐标不准确了,参考资料后发现可以使用getGlobalVisibleRect()方法。参考:http://stackoverflow.com/questions/13927718/view-gethitrectrect-not-working
第三个问题:因为Fragment中没有dispatchTouchEvent()方法,所以这里解决方法是定义一个接口,将Activity中得到的x,y坐标传递给Fragment,然后Fragment中自己寻找View,完成埋点。
第四个问题:在onCreate()中获取开始时间,在onPause中获取结束时间。
还是给一个Demo辅助说明,这里将埋点定义在基类中,更符合实际生产环境。
下面上代码:
在onCreate中做了两件事,一是记录进入的Activity并计时;二是初始化埋点列表,在实际中埋点列表数据通过服务器获取。
@Override
protected void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
startTime = System.currentTimeMillis();
Log.v("out" , "进入了:"+(Activity)this);
/*初始化一个需要埋点的列表*/
ids.add(.login);
ids.add(.register);
ids.add(.register_hidden);
ids.add(.man);
ids.add(.woman);
ids.add(.seekbar);
ids.add(.checkbox);
ids.add(.img);
ids.add(.last);
ids.add(.fragment_a_tv_login);
ids.add(.fragment_a_tv_register);
ids.add(.left);
}
然后是设置接口回调,作用是将点击坐标回传给Fragment。
public void setDispatchTouchEventable(DispatchTouchEventable dispatchTouchEventable){
this.dispatchTouchEventable = dispatchTouchEventable;
}
接下来是分发点击事件。
/*重写dispatchTouchEvent*/
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_UP){
/*获取当前点击位置,遍历布局,获取当前点击位置对应的view,根据view映射路径,与json文件中的对比*/
int x = (int) ev.getRawX();
int y = (int) ev.getRawY();
/*json串中根据Activity值只获取当前Activity的埋点View*/
for(int id:ids){
View view = findViewById(id);
if(view == null) continue;
view.getGlobalVisibleRect(rect);
if(rect.contains(x ,y )){
Log.v("out" , "埋点id:"+id);
return super.dispatchTouchEvent(ev);
}
}
/*如果运行到这了,说明上面的遍历没有找到,那么当前的view是在fragment中*/
dispatchTouchEventable.point(x , y);
}
return super.dispatchTouchEvent(ev);
}
接下来是Fragment中的写法:
@Override
public View onCreateView(LayoutInflater layoutInflater , ViewGroup viewGroup , Bundle savedInstance){
super.onCreateView(layoutInflater , viewGroup , savedInstance);
view = layoutInflater.from(getActivity()).inflate(R.layout.fragment_a , null);
ids.add(.fragment_a_tv_login);
ids.add(.fragment_a_tv_register);
((BaseActivity)getActivity()).setDispatchTouchEventable(new DispatchTouchEventable() {
@Override
public void point(int x, int y) {
for(int id:ids){
View currentview = view.findViewById(id);
if(currentview == null) continue;
currentview.getGlobalVisibleRect(rect);
if(rect.contains(x ,y )){
Log.v("out" , "埋点id:"+id);
}
}
}
});
return view;
}
总结:基本实现了无埋点技术,在实际生产环境中无须在代码中手动埋点,只需继承该基类,服务器端配置好埋点列表即可。实际应用中应该考虑埋点数据的格式,避免每点击一次都要遍历所有的id,同时,弹出框,RecyclerView,ListView等的Item点击还不能实现。这些地方需要埋点的可能性较小,如果确实需要,可以代码埋点辅助。