【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 创建 事件监听器 对应的 动态代理 | 动态代理的数据准备 | 创建调用处理程序 | 创建动态代理实例对象 )
文章目錄
- 前言
- 一、創建 事件監聽器 對應的 動態代理
- 二、動態代理 數據準備
- 三、動態代理 調用處理程序
- 四、動態代理 實例對象創建
前言
Android 依賴注入的核心就是通過反射獲取 類 / 方法 / 字段 上的注解 , 以及注解屬性 ; 在 Activity 基類中 , 獲取該注解 以及 注解屬性 , 進行相關操作 ;
在博客 【IOC 控制反轉】Android 事件依賴注入 ( 事件三要素 | 修飾注解的注解 | 事件依賴注入步驟 ) 中 , 定義了 222 個注解 ,
- 第一個是方法上的注解 , 用于修飾方法 ;
- 第二個是修飾注解的注解 , 該注解用于配置注入的方法 ( 事件監聽方法 | 監聽器類型 | 監聽器回調方法 ) ;
事件依賴注入比較復雜 , 涉及到動態代理 , 本博客分析 【IOC 控制反轉】Android 事件依賴注入 ( 事件依賴注入代碼示例 ) 事件依賴注入的詳細步驟 ;
本博客的核心是 : 使用動態代理 , 創建 View.OnClickListener 或 View.OnLongClickListener 或 View.onTouchListener 等接口的動態代理類 ;
攔截相應的 onClick , onLongClick , onTouch 方法 , 執行自己的方法 , 其它方法正常執行 ;
一、創建 事件監聽器 對應的 動態代理
為組件設置的監聽器可能是 View.OnClickListener 或 View.OnLongClickListener 或 View.onTouchListener 等監聽器 , 因此使用 靜態代理 , 需要為每個監聽器都要設置一個單獨的類 , 比較繁瑣 ;
這里使用動態代理實現上述功能 ;
動態代理是作用于接口上的 , 根據接口動態創建該接口子類的代理對象 ;
原來是設置了一個匿名內部類 , 這個匿名內部類就是代理模式中的 被代理對象 ;
textView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});現在使用 動態代理 , 創建一個 代理對象 , 代理 上述 匿名內部類 被代理對象 , 要在調用 onClick 方法時 , 注入自己的業務邏輯 ;
該動態代理中的元素梳理 :
- 目標對象 ( 主題對象 ) : View.OnClickListener 接口 ;
- 被代理對象 : View.OnClickListener 接口匿名內部類 ;
- 代理對象 : 使用 Proxy.newProxyInstance 方法 , 由 JVM 自動生成字節碼類 就是代理對象 , 之后返回一個代理對象 的實例對象 ;
- 客戶端 : 框架開發者開發的 依賴注入 工具類 , 在該工具類中執行動態代理的調用操作 ;
二、動態代理 數據準備
執行動態代理前 , 首先要知道攔截接口方法 , 以及要注入的方法 ;
攔截到接口方法后 , 替換成自己注入的方法 , 就是調用自己的方法 ;
將二者封裝到 Map 集合中 , 方便在攔截后 , 調用 Map 的 get 方法 , 查看是否有要注入的方法 ;
// 攔截 callbackMethod 方法 , 執行 method[i] 方法// 這個 method[i] 方法就是在 MainActivity 中用戶自定義方法// 被 OnClick 注解修飾的方法// 將其封裝到 Map 集合中Map<String, Method> methodMap = new HashMap<>();methodMap.put(callbackMethod, methods[i]);三、動態代理 調用處理程序
在該動態代理中 , 首先要注入 Activity 和 上面準備的 Map 集合 , Map 集合中封裝了 要攔截的接口方法 和 要注入的方法 ;
首先獲取被代理接口中的 回調的方法名稱, 該方法是 onClick 或者 onLongClick 或者 onTouch 等方法 ;
Method 方法在參數中有 , 直接調用 Method method 參數的 getName() 方法獲取接口名稱 ;
// 獲取回調的方法名稱, 該方法是 onClick 或者 onLongClick 或者 onTouch 等方法String name = method.getName();然后到 Map 集合中查找 , 是否要攔截該 接口方法 , 如果要攔截 , 肯定能從 Map 集合中獲取到要注入的方法 , 如果不需要攔截 , 獲取的結果是 null ;
// 獲取對應的被調用方法Method method1 = methodMap.get(name);如果被調用的方法 需要被攔截 , 則能獲取到被攔截后替換的方法 , 執行該注入的方法即可 ;
// 如果被調用的方法 需要被攔截 , 則能獲取到被攔截后替換的方法if (method1 != null) {// 執行用戶 Activity 中的相應方法return method1.invoke(activity, args);}如果不攔截該方法 , 則獲取的注入方法為 null , 直接返回該方法 , 注意調用 method.invoke(proxy, args) , 正常執行該接口方法即可 ;
// 其它方法正常執行return method.invoke(proxy, args);代碼示例 :
package kim.hsl.ioc_lib;import android.app.Activity;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Map;public class EventInvocationHandler implements InvocationHandler {/*** 客戶端 Activity*/private Activity activity;/*** 攔截 callbackMethod 方法 , 執行 method[i] 方法* 這個 method[i] 方法就是在 MainActivity 中用戶自定義方法* 被 OnClick 注解修飾的方法* 將其封裝到 Map 集合中*/private Map<String, Method> methodMap;public EventInvocationHandler(Activity activity, Map<String, Method> methodMap) {this.activity = activity;this.methodMap = methodMap;}/*** 攔截方法 , 并使用自己的方法替換* 如 : 發現是 onClick 方法 , 則替換成用戶自定義的方法 (被 @OnClick 注解修飾的方法)* @param proxy* @param method* @param args* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 獲取回調的方法名稱, 該方法是 onClick 或者 onLongClick 或者 onTouch 等方法String name = method.getName();// 獲取對應的被調用方法Method method1 = methodMap.get(name);// 如果被調用的方法 需要被攔截 , 則能獲取到被攔截后替換的方法if (method1 != null) {// 執行用戶 Activity 中的相應方法return method1.invoke(activity, args);}// 其它方法正常執行return method.invoke(proxy, args);} }四、動態代理 實例對象創建
調用 Proxy.newProxyInstance 方法 , 創建動態代理的 實例對象 , 傳入到代理的接口數組 , 這個接口數組元素可以是 View.OnClickListener.class 或 View.OnLongClickListener.class 或 View.OnTouchListener.class 等字節碼類 ;
在調用處理程序中 , 攔截上述接口中的方法 , 并替換成自己的方法 , 也就是用戶在 MainActivity 中使用 @OnClick 注解修飾的方法 ;
// 獲取監聽器 View.OnClickListener 接口的代理對象EventInvocationHandler eventInvocationHandler =new EventInvocationHandler(activity, methodMap);Object proxy = Proxy.newProxyInstance(listenerType.getClassLoader(), // 類加載器new Class<?>[]{listenerType}, // 接口數組eventInvocationHandler); // 調用處理程序該動態代理實例對象創建后 , 將其當做 View.OnClickListener.class 或 View.OnLongClickListener.class 或 View.OnTouchListener.class 等字節碼類的實例對象使用即可 ;
總結
以上是生活随笔為你收集整理的【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 创建 事件监听器 对应的 动态代理 | 动态代理的数据准备 | 创建调用处理程序 | 创建动态代理实例对象 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【IOC 控制反转】Android 事件
- 下一篇: 【AOP 面向切面编程】AOP 简介 (