Java使用反射和動(dòng)態(tài)代理實(shí)現(xiàn)一個(gè)View注解綁定庫(kù)
使用反射結(jié)合動(dòng)態(tài)代理實(shí)現(xiàn)一個(gè)View注解綁定庫(kù),支持View和事件綁定,代碼簡(jiǎn)潔,使用簡(jiǎn)單,擴(kuò)展性強(qiáng)。
支持的功能
@ContentView
綁定layout 替代setContentView()@BindView
綁定View 替代findViewById()@OnClick
綁定點(diǎn)擊事件 替代setOnClickListener()@OnLongClick
綁定長(zhǎng)按事件 替代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(); //事件源對(duì)象 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(); }
實(shí)現(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 { //通過(guò)反射調(diào)用findViewById得到view實(shí)例對(duì)象 Method method = clazz.getMethod("findViewById", int.class); Object view = method.invoke(object, viewId); //賦值給注解標(biāo)注的對(duì)應(yīng)字段 field.set(object, view); } catch (Exception e) { e.printStackTrace(); } } } private static void injectEvent(Object object) { Class<?> clazz = object.getClass(); //獲取到當(dāng)前頁(yè)年所有方法并遍歷 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 { //由于上邊沒(méi)有明確獲取是哪個(gè)注解,所以這里需要使用反射獲取viewId Method valueMethod = annotationType.getDeclaredMethod("value"); valueMethod.setAccessible(true); int viewId = (int) valueMethod.invoke(annotation); //通過(guò)反射findViewById獲取到對(duì)應(yīng)的view Method findViewByIdMethod = clazz.getMethod("findViewById", int.class); Object view = findViewByIdMethod.invoke(object, viewId); //通過(guò)反射獲取到view中對(duì)應(yīng)的setCommonListener方法 Method viewMethod = view.getClass().getMethod(setCommonListener, commonListener); //使用動(dòng)態(tài)代理監(jiān)聽(tīng)回調(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使用反射和動(dòng)態(tài)代理實(shí)現(xiàn)一個(gè)View注解綁定庫(kù)的文章就介紹到這了,更多相關(guān)View注解綁定庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
idea2020中復(fù)制一個(gè)微服務(wù)實(shí)例的方法
這篇文章主要介紹了idea2020中復(fù)制一個(gè)微服務(wù)實(shí)例的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09Kafka利用Java實(shí)現(xiàn)數(shù)據(jù)的生產(chǎn)和消費(fèi)實(shí)例教程
這篇文章主要給大家介紹了關(guān)于Kafka利用Java實(shí)現(xiàn)數(shù)據(jù)的生產(chǎn)和消費(fèi)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01關(guān)于Java中byte[]?和?String互相轉(zhuǎn)換問(wèn)題
這篇文章主要介紹了Java中byte[]?和?String互相轉(zhuǎn)換問(wèn)題,通過(guò)用例給大家介紹了通過(guò)String類將String轉(zhuǎn)換成byte[]或者byte[]轉(zhuǎn)換成String,具體實(shí)例代碼跟隨小編一起看看吧2022-01-01純Java實(shí)現(xiàn)數(shù)字證書(shū)生成簽名的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇純Java實(shí)現(xiàn)數(shù)字證書(shū)生成簽名的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08詳解SimpleDateFormat的線程安全問(wèn)題與解決方案
這篇文章主要介紹了SimpleDateFormat的線程安全問(wèn)題與解決方案,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03Java實(shí)現(xiàn)mysql數(shù)據(jù)庫(kù)的自動(dòng)備份和自動(dòng)還原
這篇文章主要為大家詳細(xì)介紹了如何通過(guò)Java實(shí)現(xiàn)mysql數(shù)據(jù)庫(kù)的自動(dòng)備份和自動(dòng)還原,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-11-11