无埋点操作,是通过gradle的Transform API在编译期扫描整个项目生成的class文件,再利用ASM API对class文件插入我们的埋点方法来实现的。
在各种事件方法里插桩埋点,基本上满足我们的大部分埋点需求,但是产品会有这样的需求,想看看用户在某个界面里哪些区域点击比较频繁,就需要知道用户点击的坐标。获取点击事件可以办到,还可以拿到点击事件里的View,但是无法获取点击的屏幕坐标。那点击屏幕坐标在哪里获取呢?在View的dispatchTouchEvent里,如果我们在此处插桩,可以拿到它的参数MotionEvent,通过它我们就可以拿到控件的点击坐标。
但是dispatchTouchEvent是系统类View的方法,项目编译的时候是没有android.jar供Transform扫描的。办法是可以通过其他方式实现,比如每打开一个界面都创建一个透明层在屏幕上,通过自定义透明层View来重写dispatchTouchEvent获取MotionEvent。或者所有的控件都自定义View的方式重写dispatchTouchEvent获取MotionEvent。这两种方式开销都比较大,难以维护,不可取。
这里介绍通过另一种方式来实现。大家都知道android系统出的support包和现在的androidx包都是为了向下兼容,使得老控件,如textview、edittext等等,可以像Appcompattextview、Appcompatedittext一样有更好的着色和主题样式。但是怎么实现呢?答案在Activity启动过程里。Activity的启动过程大家自行百度,这里先讲oncreate方法
在AppcompatActivity的onCreate方法里,有一个getDelegate()方法,返回AppCompatDelegate,
进去后,可以看到new了一个AppCompatDelegateImpl实现类,这个实现类又继承自AppCompatDelegate。
到这里还没看到关键信息,我们先看下xml布局文件是怎么映射成控件view的,
在AppCompatDelegateImpl找createView方法,在createView里有一个AppCompatViewInflater类,默认类名或设置为null就new一个AppCompatViewInflater,否则就反射获取AppCompatViewInflater对象。
到这里,AppCompatActivity的getDelegate()方法,只是new了一个AppCompatDelegateImpl类,并未看到实质的东西。在里面找一下可以看到createView这个方法,可以猜到肯定跟这个createView方法有关系。那它是什么时候被调用的呢,我们回到AppCompatActivity,getDelegate()方法的下一行delegate.installViewFactory();
,进去后可以看到实例化了系统服务LAYOUT_INFLATER_SERVICE,并把它设置进setFactory2方法里,
可以看到factory赋值给mFactory2接口类
回到setContentView()方法,我们可以看到LayoutInflater.from(mContext).inflate(resId, contentParent);
,步骤是在LayoutInflater里先用xmlpullparser解析xml,根据tag来生成对应的控件
最终还是通过一系列调用createViewFromTag->tryCreateView->mFactory2.onCreateView(接口回调到AppCompatDelegateImpl
)->onCreateView->createView->mAppCompatViewInflater.createView,最后进入AppCompatViewInflater类里,可以看