版權宣告:
本賬號釋出文章均來自公眾號,承香墨影(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
包下面:
可以看到這些被重寫的 UI 控制元件都是 AppCompat 開頭的,但是如果重寫了這麼多控制元件,現有專案直接硬替換起來,工作量就會非常大,所以 AppCompatDelegate 這種以代理的方式自動為我們替換所使用的 UI 控制元件的功能就非常的有必要了。
2、AppCompatDelegate 是如何工作的
在 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…