版權聲明:android
本帳號發佈文章均來自公衆號,承香墨影(cxmyDev),版權歸承香墨影全部。app
未經容許,不得轉載。post
前面在公衆號裏的文章中講到,美團的無埋點方案就是,重寫全部的 UI 控件,而後對其事件進行代理監聽,最終在觸發事件的時候,去判斷是否須要對這次事件進行統計點的上報。因此引起出,如何低成本的替換掉已有項目內的 UI 控件。插件
兩個方案,其中一個是借鑑 Android v7 支持的思路,經過 AppCompatDelegate 代理,來自動替換咱們須要的 UI 控件。設計
今天主要就這個主題,進行講解。3d
說到 Android support v7 包內的代理思路,是經過 AppCompatDelegate 來實現的。代理
AppCompat 在最開始出如今 v7 包中的時候,其實做用很是的小,只是爲了讓 API level 7+ 的設備,也可使用 ActionBar 。而在 Support v7:21 版本以後,AppCompat 承擔了跟多的責任,能夠爲 API Level 7+ 的設備帶來 Material Color Palette 、Widget 着色、ToolBar 等功能。並且以前推薦使用的 ActionBarActivity 也再也不推薦使用,取而代之的是 AppCompatActivity 。code
AppCompatActivity 其實內部的實現原理也和以前的 ActionBarActivity 實現不一樣,它是經過是經過 AppCompatDelegate 來實現的。AppCompatActivity 將全部的生命週期相關的會掉,都交由 AppCompatDelegate 來處理。cdn
可是實際是他們並無直接的關聯關係,咱們也能夠直接使用 AppCompatDelegate 來放入咱們本身實現的 Activity 中,可是這樣就會更麻煩,通常也不推薦這樣使用。對象
AppCompat 爲了支持 MD 的效果,須要其內部的控件都具備自動着色功能,這樣能夠保持 App 在設計上具備一致的體驗和提升承認度。而這些是本來的 UI 控件所不具有的,因此它只好將其須要的 UI 控件所有重寫一遍來支持這個效果。
這些被重寫的 UI 控件,都在 android.support.v7.widget
包下面:
能夠看到這些被重寫的 UI 控件都是 AppCompat 開頭的,可是若是重寫了這麼多控件,現有項目直接硬替換起來,工做量就會很是大,因此 AppCompatDelegate 這種以代理的方式自動爲咱們替換所使用的 UI 控件的功能就很是的有必要了。
在 AppCompatActivity 中,使用 getDelegate() 方法來得到 AppCompatDelegate 對象的。
而這個 AppCompatDelegate.create() 方法就是其作代理支持的實現。
能夠看到它除了對 Activity 有支持以外,還對 Dialog 也有支持。而且在其中,分別根據不一樣的 API Level 進行不一樣的實現,並且最低能支持到 API Level 9。
雖然這裏看到它經過 API Level 作了區分判斷來作具體的實現,可是相似這種 AppCompatDelegateImplVxx 的類,都高版本的繼承低版本的。而 AppCompatDelegateImplV9 中,就是經過 LayoutInflaterFactory 接口來實現 UI 控件替換的代理。
在解析 ViewTree 的時候,會調用 createView() 方法來獲得 View 對象,而在其中,又是經過 mAppCompatViewInFlater.createView() 來真實的獲取 View 的。
而在 mAppCompatViewInFlater.createView() 中,就是經過 UI 控件的名稱,來替換掉咱們須要的 AppCompat 的 UI 控件。
因此到這裏,就能夠發現,若是咱們也須要利用 AppCompatDelegate 來替換掉咱們須要的 UI 控件,只須要本身實現一個 AppCompatDelegate 以及其中的 callActivityOnCreateView() 方法。在實際使用的 AppCompatActivity 的父類中,重寫 getDelegate 方法,將方法的返回值替換成咱們以前修改過的 AppCompatDelegate ,就能夠實現自動替換 UI 控件了。
寫到這裏,天然是要舉個例子來講明問題。
首先咱們重寫一個 Button 控件,對其中的 onClick 事件作一個代理監聽。
再實現一個咱們本身的 AppCompatDelegate 。
而後本身定一個 AppCompatDelegate 根據類,用於返回 AppCompatDelegate,這裏只是作演示,因此直接返回上面定義的 AppCompatDelegate 類了。
最終,在使用的 Activity 中,重寫 getDelegate() 方法,作到替換。
運行以後,從輸出Log中能夠看到咱們須要的內容。
在回到咱們須要作無埋點統計的方案內的話題中,實際上,咱們須要的是用他來替換掉咱們重寫後的控件。而使用 AppCompatDelegate 的方案,只能重寫咱們本身使用的 UI 控件,沒法替換掉第三方庫中重寫的 UI 控件。
雖然咱們知道有這麼個缺陷,可是實際上,在項目內用到第三方庫中的 UI 控件的場景畢竟是有限的,咱們只須要在使用以前對其進行再封裝,或者對這些使用第三方庫的 UI 控件的位置,嚴格保證不遺漏統計點,這樣的方案也是能夠被咱們接受的。
下一篇再講解一下如何經過 Gradle 插件的形式,在編譯期間,替換掉三方庫內的 UI 控件。
那咱們敬請期待吧。
本文參加掘金技術徵文:juejin.im/post/58d8e9…