ButterKnife的使用極大方便了Android程序員的開發,實際上,我們可以自己模仿一下實現。
首先就是要了解Java註解的使用。
我們首先要聲明一個@interface,也就是註解類:
@Target(ElementType.FIELD)//表示用在字段s上
@Retention(RetentionPolicy.RUNTIME)//表示在生命週期是運行時
public @interface ViewBinder {
int id() default -1;
String method() default "";
String type() default "";
}
@interface是用於自定義註解的,它裏面定義的方法的聲明不能有參數,也不能拋出異常,並且方法的返回值被限制爲簡單類型、String、Class、emnus、@interface,和這些類型的數組。
註解@Target也是用來修飾註解的元註解,它有一個屬性ElementType也是枚舉類型,值爲:ANNOTATION_TYPE,CONSTRUCTOR
,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER和TYPE,如@Target(ElementType.METHOD) 修飾的註解表示該註解只能用來修飾在方法上。
@RetentionRetention註解表示需要在什麼級別保存該註釋信息,用於描述註解的生命週期,它有一個RetentionPolicy類型的value,是一個枚舉類型,它有以下的幾個值:
1.用@Retention(RetentionPolicy.SOURCE)修飾的註解,指定註解只保留在源文件當中,編譯成類文件後就把註解去掉;
2.用@Retention(RetentionPolicy.CLASS)修飾的註解,指定註解只保留在源文件和編譯後的class 文件中,當jvm加載類時就把註解去掉;
3.用@Retention(RetentionPolicy.RUNTIME )修飾的註解,指定註解可以保留在jvm中,這樣就可以使用反射獲取信息了。
默認是RUNTIME,這樣我們才能在運行的時候通過反射獲取並做對應的邏輯處理。
接下來我們就是利用反射來獲取註解的屬性以及做相應的處理:
public class ViewBinderParser implements Parsable {
private ViewBinderParser() {
}
public static void inject(Object object) {
ViewBinderParser parser = new ViewBinderParser();
try {
parser.parse(object);
} catch (Exception e) {
LogUtil.e(e.toString());
}
}
@Override
public void parse(final Object object) throws Exception {
View view = null;
final Class<?> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();//獲得Activity中聲明的字段
for (Field field : fields) {
// 查看這個字段是否有我們自定義的註解類標誌的
if (field.isAnnotationPresent(ViewBinder.class)) {
ViewBinder inject = field.getAnnotation(ViewBinder.class);
int id = inject.id();
if (id < 0) {
throw new Exception("id must not be null");
}
if (id > 0) {
field.setAccessible(true);
if (object instanceof View) {
view = ((View) object).findViewById(id);
} else if (object instanceof Activity) {
view = ((Activity) object).findViewById(id);
}
field.set(object, view);//給我們要找的字段設置值
String methodName = inject.method();
if (!methodName.equals("")) {
OnEventListener listener = new OnEventListener(object);
String type = inject.type();
if (type.equals("")) {
throw new Exception("Please input the type of Method,such as 'method=OnClick'");
}
if (type.equals("OnClick")) {
listener.setOnClick(id, methodName);
}
}
}
}
}
}
}
我們通過inject將添加註解的對象傳進來,然後進入註解屬性的解析方法中。
利用反射獲取所有聲明的字段,然後再利用isAnnotationPresent方法查看該字段是否有添加的註解類型,再從該字段中獲取註解,通過定義好的方法獲取到相應的屬性值。我們這裏獲取到對應的View的id,然後在這裏進行View的初始化,以及事件的綁定。
完成事件的綁定還需要一個類:
public class OnEventListener {
private Object object;
public OnEventListener(Object object) {
this.object = object;
}
public void setOnClick(int id, final String methodName) {
View view = null;
if (object instanceof View) {
view = ((View) object).findViewById(id);
} else if (object instanceof Activity) {
view = ((Activity) object).findViewById(id);
}
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MethodModel methodModel = new MethodModel();
Class clazz = methodModel.getClass();
try {
Method method = clazz.getMethod(methodName, new Class[]{});
method.invoke(methodModel, new Object[]{});
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
});
}
}
目前只是實現了點擊事件的綁定。
接着我們就可以這樣使用我們自定義的註解了:
public class MainActivity extends ActionBarActivity {
@ViewBinder(id = R.id.cet_receiver)
protected CustomEditText cetReceiver;
@ViewBinder(id = R.id.cet_cc)
protected CustomEditText cetCC;
@ViewBinder(id = R.id.cet_content)
protected CustomEditText cetContent;
@ViewBinder(id = R.id.cet_subject)
protected CustomEditText cetSubject;
@ViewBinder(id = R.id.iv_receiver)
protected ImageView ivReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewBinderParser.inject(this);
ivReceiver.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cetCC.setVisibility(View.VISIBLE);
}
});
}
}
註解的使用可以讓我們的代碼更加簡潔,但前提是,這種前提是否有必要。