美團點評無埋點方案 - 利用 AppCompatDetegale 替換控制元件 | 掘金技術徵文

承香墨影發表於2017-04-25

版權宣告:

本賬號釋出文章均來自公眾號,承香墨影(cxmyDev),版權歸承香墨影所有。

未經允許,不得轉載。

一、前言

前面在公眾號裡的文章中講到,美團的無埋點方案就是,重寫所有的 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 控制元件。

那我們敬請期待吧。

本文參加掘金技術徵文:juejin.im/post/58d8e9…

美團點評無埋點方案 - 利用 AppCompatDetegale 替換控制元件 | 掘金技術徵文
公眾號二維碼.jpg

相關文章