Java使用反射和動態(tài)代理實現(xiàn)一個View注解綁定庫
更新時間:2022年05月10日 15:54:33 作者:木水Code
這篇文章主要介紹了Java使用反射和動態(tài)代理實現(xiàn)一個View注解綁定庫,代碼簡潔,使用簡單,擴展性強,結合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
使用反射結合動態(tài)代理實現(xiàn)一個View注解綁定庫,支持View和事件綁定,代碼簡潔,使用簡單,擴展性強。
支持的功能
@ContentView綁定layout 替代setContentView()@BindView綁定View 替代findViewById()@OnClick綁定點擊事件 替代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);
//賦值給注解標注的對應字段
field.set(object, view);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void injectEvent(Object object) {
Class<?> clazz = object.getClass();
//獲取到當前頁年所有方法并遍歷
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獲取到對應的view
Method findViewByIdMethod = clazz.getMethod("findViewById", int.class);
Object view = findViewByIdMethod.invoke(object, viewId);
//通過反射獲取到view中對應的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í)行被標注的方法
return declaredMethod.invoke(object, null);
}
}
);
//調(diào)用view的setCommonListener方法
viewMethod.invoke(view, proxy);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
復制代碼使用
@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;
}
}到此這篇關于Java使用反射和動態(tài)代理實現(xiàn)一個View注解綁定庫的文章就介紹到這了,更多相關View注解綁定庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Kafka利用Java實現(xiàn)數(shù)據(jù)的生產(chǎn)和消費實例教程
這篇文章主要給大家介紹了關于Kafka利用Java實現(xiàn)數(shù)據(jù)的生產(chǎn)和消費的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-01-01
純Java實現(xiàn)數(shù)字證書生成簽名的簡單實例
下面小編就為大家?guī)硪黄僇ava實現(xiàn)數(shù)字證書生成簽名的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-08-08
詳解SimpleDateFormat的線程安全問題與解決方案
這篇文章主要介紹了SimpleDateFormat的線程安全問題與解決方案,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-03-03
Java實現(xiàn)mysql數(shù)據(jù)庫的自動備份和自動還原
這篇文章主要為大家詳細介紹了如何通過Java實現(xiàn)mysql數(shù)據(jù)庫的自動備份和自動還原,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下2024-11-11

