Java使用反射和動態(tài)代理實現(xiàn)一個View注解綁定庫
使用反射結(jié)合動態(tài)代理實現(xiàn)一個View注解綁定庫,支持View和事件綁定,代碼簡潔,使用簡單,擴(kuò)展性強(qiáng)。
支持的功能
@ContentView
綁定layout 替代setContentView()@BindView
綁定View 替代findViewById()@OnClick
綁定點(diǎn)擊事件 替代setOnClickListener()@OnLongClick
綁定長按事件 替代setOnLongClickListener()
代碼
注解類
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ContentView { int value(); }
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface BindView { int value(); }
@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface OnEvent { //訂閱方式 String setCommonListener(); //事件源對象 Class<?> commonListener(); }
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @OnEvent(setCommonListener = "setOnClickListener", commonListener = View.OnClickListener.class) public @interface OnClick { int value(); }
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @OnEvent(setCommonListener = "setOnLongClickListener", commonListener = View.OnLongClickListener.class) public @interface OnLongClick { int value(); }
實現(xiàn)類
public class MsInjector { public static void inject(Object object) { injectContentView(object); injectView(object); injectEvent(object); } private static void injectContentView(Object object) { Class<?> clazz = object.getClass(); //獲取到ContentView注解 ContentView contentView = clazz.getAnnotation(ContentView.class); if (contentView == null) { return; } //獲取到注解的值,也就是layoutResID int layoutResID = contentView.value(); try { //反射出setContentView方法并調(diào)用 Method method = clazz.getMethod("setContentView", int.class); method.invoke(object, layoutResID); } catch (Exception e) { e.printStackTrace(); } } private static void injectView(Object object) { Class<?> clazz = object.getClass(); //獲取到所有字段并遍歷 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); //獲取字段上的BindView注解 BindView bindView = field.getAnnotation(BindView.class); if (bindView == null) { continue; } //獲取到viewId int viewId = bindView.value(); try { //通過反射調(diào)用findViewById得到view實例對象 Method method = clazz.getMethod("findViewById", int.class); Object view = method.invoke(object, viewId); //賦值給注解標(biāo)注的對應(yīng)字段 field.set(object, view); } catch (Exception e) { e.printStackTrace(); } } } private static void injectEvent(Object object) { Class<?> clazz = object.getClass(); //獲取到當(dāng)前頁年所有方法并遍歷 Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { declaredMethod.setAccessible(true); //獲取方法上的所有注解并遍歷 Annotation[] annotations = declaredMethod.getDeclaredAnnotations(); for (Annotation annotation : annotations) { //獲取注解本身 Class<? extends Annotation> annotationType = annotation.annotationType(); //獲取注解上的OnEvent注解 OnEvent onEvent = annotationType.getAnnotation(OnEvent.class); if (onEvent == null) { continue; } //拿到注解中的元素 String setCommonListener = onEvent.setCommonListener(); Class<?> commonListener = onEvent.commonListener(); try { //由于上邊沒有明確獲取是哪個注解,所以這里需要使用反射獲取viewId Method valueMethod = annotationType.getDeclaredMethod("value"); valueMethod.setAccessible(true); int viewId = (int) valueMethod.invoke(annotation); //通過反射findViewById獲取到對應(yīng)的view Method findViewByIdMethod = clazz.getMethod("findViewById", int.class); Object view = findViewByIdMethod.invoke(object, viewId); //通過反射獲取到view中對應(yīng)的setCommonListener方法 Method viewMethod = view.getClass().getMethod(setCommonListener, commonListener); //使用動態(tài)代理監(jiān)聽回調(diào) Object proxy = Proxy.newProxyInstance( clazz.getClassLoader(), new Class[]{commonListener}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //最終執(zhí)行被標(biāo)注的方法 return declaredMethod.invoke(object, null); } } ); //調(diào)用view的setCommonListener方法 viewMethod.invoke(view, proxy); } catch (Exception e) { e.printStackTrace(); } } } } } 復(fù)制代碼
使用
@ContentView(R.layout.activity_main) public class MainActivity extends AppCompatActivity { @BindView(R.id.button1) private Button button1; @BindView(R.id.button2) Button button2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MsInjector.inject(this); } @OnClick(R.id.button1) public void clickButton1() { Toast.makeText(this, "click button1", Toast.LENGTH_SHORT).show(); } @OnClick(R.id.button2) public void clickButton2() { Toast.makeText(this, "click button2", Toast.LENGTH_SHORT).show(); } @OnLongClick(R.id.button1) public boolean longClickButton1() { Toast.makeText(this, "long click button1", Toast.LENGTH_SHORT).show(); return false; } @OnLongClick(R.id.button2) public boolean longClickButton2() { Toast.makeText(this, "long click button2", Toast.LENGTH_SHORT).show(); return false; } }
到此這篇關(guān)于Java使用反射和動態(tài)代理實現(xiàn)一個View注解綁定庫的文章就介紹到這了,更多相關(guān)View注解綁定庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Kafka利用Java實現(xiàn)數(shù)據(jù)的生產(chǎn)和消費(fèi)實例教程
這篇文章主要給大家介紹了關(guān)于Kafka利用Java實現(xiàn)數(shù)據(jù)的生產(chǎn)和消費(fèi)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01關(guān)于Java中byte[]?和?String互相轉(zhuǎn)換問題
這篇文章主要介紹了Java中byte[]?和?String互相轉(zhuǎn)換問題,通過用例給大家介紹了通過String類將String轉(zhuǎn)換成byte[]或者byte[]轉(zhuǎn)換成String,具體實例代碼跟隨小編一起看看吧2022-01-01純Java實現(xiàn)數(shù)字證書生成簽名的簡單實例
下面小編就為大家?guī)硪黄僇ava實現(xiàn)數(shù)字證書生成簽名的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-08-08詳解SimpleDateFormat的線程安全問題與解決方案
這篇文章主要介紹了SimpleDateFormat的線程安全問題與解決方案,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-03-03Java實現(xiàn)mysql數(shù)據(jù)庫的自動備份和自動還原
這篇文章主要為大家詳細(xì)介紹了如何通過Java實現(xiàn)mysql數(shù)據(jù)庫的自動備份和自動還原,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-11-11