github地址, 覺得不錯的歡迎給個star :https://github.com/zhaokidd/AndroidCLickInjectUtil
在項目中對view進行初始化的時候,我們經常要寫大量重復的 findViewById() 和 setOnclickListener 方法,這種無意義的重復性勞動相當耗費時間.
通過反射和注解,可以實現一種簡單高效的方法來初始化view對象.
@ClickInject(R.id.button)
private Button button;
@ClickInject(R.id.textview)
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ClickUtil.inject(this, this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
Toast.makeText(MainActivity.this, "Click Me", Toast.LENGTH_SHORT)
.show();
break;
case R.id.textview:
Toast.makeText(MainActivity.this, "Hello World", Toast.LENGTH_SHORT)
.show();
break;
default:
break;
}
}
先看demo,代碼中通過一行 ClickUtil.inject(this,this)
就優雅地實現了對 TextView和Button的初始化,你所需做的就只是在需要初始化的view組件聲明的地方用注解提前聲明
@ClickInject(R.id.textview)
private TextView textView;```
這種方法使代碼看上去要優雅了很多,同時避免了很多冗余的聲明代碼.
#### 如何實現?
```java
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
/**
* @author zy
* */
public @interface ClickInject {
int value();
}
首先,我們來自定義一個注解,這個自定義注解接受一個 int 值變量作為參數,這個參數就是要初始化的view對象對應在xml文件中的id.同時用兩個元注解來修飾這個自定義注解, @Target 表明該注解修飾的是某個類中聲明的變量, @Retention 來表明該注解的生存周期.
/**
* @param holder
* The holder holds the views
* @param injectObject
* The parent view where the child views belong to
*
* */
public static void inject(Object holder, Object injectObject,
OnClickListener listener) {
Class<?> clazzHoler = holder.getClass();
Class<?> clazzView = injectObject.getClass();
Field[] fields = clazzHoler.getDeclaredFields();
for (Field field : fields) {
ClickInject clickInjectAnnotation = field
.getAnnotation(ClickInject.class);
if (clickInjectAnnotation != null) {
int viewId = clickInjectAnnotation.value();
if (viewId > 0) {
try {
Method method = clazzView.getMethod(
METHOD_FIND_VIEW_BY_ID, int.class);
Object resObject = method.invoke(injectObject, viewId);
field.setAccessible(true);
field.set(holder, resObject);
if (resObject != null) {
Class<?> clazzInject = resObject.getClass();
Method method2 = clazzInject.getMethod(
METHOD_SET_LISTENER, OnClickListener.class);
method2.invoke(resObject, listener);
} else {
Log.e(TAG, "view has not been found");
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
Log.e(TAG, "res id is not illegal");
}
}
}
}
接著分析下核心的 inject() 方法.這個方法接受三個參數。
- 第一個參數 holder 是裝載要初始化的view的容器,例如 Activity ,通常會把view對象聲明在這些容器中.
- 第二個參數 injectObject 是要初始化的view對象的parent view,我們對通過反射來對 injectObject 對象執行 findViewById() 方法來找到子view,接著通過反射對子view執行setOnClickListener() 方法.
- 第三個參數 listener,要設定的 onClickListener
不得不說反射是開發中經常能用的一把利器,雖然會犧牲性能,但在很多場景下使用反射能提高開發效率.