一、點選頻控正常做
由于曆史原因 ,FM項目中存在 多種方式 :
1)調用處分散實作
缺點:代碼備援 ,實作不統一 (如時間間隔頻率不一樣等等)
2)定義成工具類使用(如下 ClickUtils)
ClickUtils 工具類克服了1)中問題,但是也存在一些問題,如 每個調用處需要手動組合一個tag (一般是檔案名+ 方法名 )。
有些人可能會剔除都是點選事件直接用viewId 不就可以了嗎 ,如果使用viewId 勢必要傳一個View 進去,這樣大大限制了使用場景 (目前 FM 已經使用DataBinding),這種方式被抛棄。
圖1 ClickUtils 定義
如果想自動化生成tag 也有其他辦法 :如 new Throwable().getStackTrace() ,缺點有一定性能損耗。
圖2 通過 StackTrace 擷取class 名和 行号
二 、AOP+Annotation 實作
那有沒有更簡單的方式 去實作 :去備援 、更簡潔自動化 ,對應AOP+Annotation 實作方式應運而生。
原理簡單如下 :通過Annotation 标注那些方法需要判斷 ,同過AOP 方式找到@SingleClick 使用的切點 ,自動生成唯一的 tag (這裡是檔案名 + 行号 )
(1)時間間隔定值實作方式
1)Aspect 插件Android gradle 開發環境配置
圖3 Aspect 插件 配置
2)定義@SingleClick注解
圖4 定義@SingleClick注解
3)定義切點處理方法 類 SingleClickAspect
利用joint.S=sourceLocation 擷取檔案名 和 行号 ,組合成可唯一确認的tag ,到此功能完全實作。
圖5 SingleClickAspect 定義
(2)時間間隔可設方式
1)定義帶預設值方法注解
圖6 定義帶預設值方法注解
2)對應修改SingleClickAspect修改
由于本次需要擷取注解上的設定值 ,因而這裡需要使用MethodSignature 方法,對照改寫如下,使用方式 @SingleClick 或者@SingleClick(xxx)
圖7 修改後SingleClickAspect 定義
運作發現,Debug 版本沒有問題 ,Release 版本 挂掉了 ,報錯資訊指出 :method 為null 。細想都是按照@SingleClick 注解找的,method 怎麼能為空,而且項目中也對所有注解混淆進行了Keep ,是以将問題鎖定在AOP 的實作上。
1)使用反編譯工具jadx 檢視Rebase 和Debug 版本後的代碼 與插裝之前做對比
觀察的是AlbumShowViewModel::onMoreClick() 方法 ,debug 版本如下 :
圖 8 debug 版本插裝後的代碼
圖 9 release 版本插裝後的代碼
2)導緻method 為null的原因
對比release 版本和debug 版本知 ,插裝時使用的是makeMethodSig ,第三個參數declaringType 傳的就是class 名字 ,直接使用Class.forName(declaringType) 建立class ,由于插裝後 ,release 版本類名混淆,導緻這裡發生異常 ,method 為null。
圖10 插裝實作
3)解決方式
解決方式很簡易 :keep 住使用@SingleClick注解的類即可
圖11 解決方式
綜上兩種方式問題,FM項目最終選擇時間間隔定值方式作為最終方案。