美团点评无埋点方案-利用AppCompatDetegale替换控件

美团点评无埋点方案-利用AppCompatDetegale替换控件

版权声明:

本公众号发布的所有文章,均属于原创,版权归本公众号所有。

未经允许,不得转载。

一、前言

前面在公众号里的文章中讲到,美团的无埋点方案就是,重写所有的 UI 控件,然后对其事件进行代理监听,最终在触发事件的时候,去判断是否需要对此次事件进行统计点的上报。所以引发出,如何低成本的替换掉已有项目内的 UI 控件。

两个方案,其中一个是借鉴 Android v7 支持的思路,通过 AppCompatDelegate 代理,来自动替换我们需要的 UI 控件。

今天主要就这个主题,进行讲解。

二、v7 的代理思路

说到 Android support v7 包内的代理思路,是通过 AppCompatDelegate 来实现的。

AppCompat 在最开始出现在 v7 包中的时候,其实作用非常的小,只是为了让 API level 7+ 的设备,也可以使用 ActionBar 。而在 Support v7:21 版本之后,AppCompat 承担了跟多的责任,可以为 API Level 7+ 的设备带来 Material Color Palette 、Widget 着色、ToolBar 等功能。而且之前推荐使用的 ActionBarActivity 也不再推荐使用,取而代之的是 AppCompatActivity 。

AppCompatActivity 其实内部的实现原理也和之前的 ActionBarActivity 实现不同,它是通过是通过 AppCompatDelegate 来实现的。AppCompatActivity 将所有的生命周期相关的会掉,都交由 AppCompatDelegate 来处理。

但是实际是他们并没有直接的关联关系,我们也可以直接使用 AppCompatDelegate 来放入我们自己实现的 Activity 中,但是这样就会更麻烦,一般也不推荐这样使用。

1、AppCompat为什么而存在

AppCompat 为了支持 MD 的效果,需要其内部的控件都具有自动着色功能,这样可以保持 App 在设计上具有一致的体验和提高认可度。而这些是原本的 UI 控件所不具备的,所以它只好将其需要的 UI 控件全部重写一遍来支持这个效果。

这些被重写的 UI 控件,都在 android.support.v7.widget 包下面:

美团点评无埋点方案-利用AppCompatDetegale替换控件

可以看到这些被重写的 UI 控件都是 AppCompat 开头的,但是如果重写了这么多控件,现有项目直接硬替换起来,工作量就会非常大,所以 AppCompatDelegate 这种以代理的方式自动为我们替换所使用的 UI 控件的功能就非常的有必要了。

2、AppCompatDelegate 是如何工作的

在 AppCompatActivity 中,使用 getDelegate() 方法来获得 AppCompatDelegate 对象的。

美团点评无埋点方案-利用AppCompatDetegale替换控件

而这个 AppCompatDelegate.create() 方法就是其做代理支持的实现。

美团点评无埋点方案-利用AppCompatDetegale替换控件

可以看到它除了对 Activity 有支持之外,还对 Dialog 也有支持。并且在其中,分别根据不同的 API Level 进行不同的实现,而且最低能支持到 API Level 9。

虽然这里看到它通过 API Level 做了区分判断来做具体的实现,但是类似这种 AppCompatDelegateImplVxx 的类,都高版本的继承低版本的。而 AppCompatDelegateImplV9 中,就是通过 LayoutInflaterFactory 接口来实现 UI 控件替换的代理。

美团点评无埋点方案-利用AppCompatDetegale替换控件

在解析 ViewTree 的时候,会调用 createView() 方法来得到 View 对象,而在其中,又是通过 mAppCompatViewInFlater.createView() 来真实的获取 View 的。

而在 mAppCompatViewInFlater.createView() 中,就是通过 UI 控件的名称,来替换掉我们需要的 AppCompat 的 UI 控件。

美团点评无埋点方案-利用AppCompatDetegale替换控件

所以到这里,就可以发现,如果我们也需要利用 AppCompatDelegate 来替换掉我们需要的 UI 控件,只需要自己实现一个 AppCompatDelegate 以及其中的 callActivityOnCreateView() 方法。在实际使用的 AppCompatActivity 的父类中,重写 getDelegate 方法,将方法的返回值替换成我们之前修改过的 AppCompatDelegate ,就可以实现自动替换 UI 控件了。

三、举个例子

写到这里,自然是要举个例子来说明问题。

首先我们重写一个 Button 控件,对其中的 onClick 事件做一个代理监听。

美团点评无埋点方案-利用AppCompatDetegale替换控件

再实现一个我们自己的 AppCompatDelegate 。

美团点评无埋点方案-利用AppCompatDetegale替换控件

然后自己定一个 AppCompatDelegate 根据类,用于返回 AppCompatDelegate,这里只是做演示,所以直接返回上面定义的 AppCompatDelegate 类了。

美团点评无埋点方案-利用AppCompatDetegale替换控件

最终,在使用的 Activity 中,重写 getDelegate() 方法,做到替换。

美团点评无埋点方案-利用AppCompatDetegale替换控件

运行之后,从输出Log中可以看到我们需要的内容。

美团点评无埋点方案-利用AppCompatDetegale替换控件

四、回到主要的话题

在回到我们需要做无埋点统计的方案内的话题中,实际上,我们需要的是用他来替换掉我们重写后的控件。而使用 AppCompatDelegate 的方案,只能重写我们自己使用的 UI 控件,无法替换掉第三方库中重写的 UI 控件。

虽然我们知道有这么个缺陷,但是实际上,在项目内用到第三方库中的 UI 控件的场景毕竟是有限的,我们只需要在使用之前对其进行再封装,或者对这些使用第三方库的 UI 控件的位置,严格保证不遗漏统计点,这样的方案也是可以被我们接受的。

五、结语

下一篇再讲解一下如何通过 Gradle 插件的形式,在编译期间,替换掉三方库内的 UI 控件。

那我们敬请期待吧。

美团点评无埋点方案-利用AppCompatDetegale替换控件