Android开发中不可避免的是findViewById()这样的繁琐事情,往往我们在写这些findViewById()的的时候有没有种想吐的感觉?这项工作纯属是个没营养的体力活,so Android衍生出了很多开源框架通过注解的方式来绑定控件,省去这项繁琐的体力活。这里也不介绍这些框架,而是忙碌的时间刚好结束可以休息一两天,但是上班对着电脑又不干活貌似有点无聊,于是就打算写个关于注解简单使用的博文出来,废话不多说正文开始。
原理:原理是在Activity加载完后通过找到注解的字段,再通过JAVA的反射机制动态个这个字段设置值。
一、定义注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)//表示正在运行
public @interface BindView {
int id(); //注解属性,同findViewById()的值
boolean click() default false; //是否设置了点击事件
}
这里解释下 @Target ,@Retention这两个是什么意思,Target ,Retention这种注解叫元注解,其中分别的意思是:
1、Target的功能就是表明你这个注解是用在什么地方,它值是一个枚举类型
public enum ElementType {
/**
* Class, interface or enum declaration. 用于描述类、接口(包括注解类型)
*/
TYPE,
/**
* Field declaration. 字段声明
*/
FIELD,
/**
* Method declaration. 方法声明
*/
METHOD,
/**
* Parameter declaration. 参数声明
*/
PARAMETER,
/**
* Constructor declaration. 构造器声明
*/
CONSTRUCTOR,
/**
* Local variable declaration. 局部变量
*/
LOCAL_VARIABLE,
/**
* Annotation type declaration. 注释类型声明。
*/
ANNOTATION_TYPE,
/**
* package declaration. 用于描述包
*/
PACKAGE
}
2、Retention大概意思是注解的生命周期什么时候生效。
public enum RetentionPolicy {
/**
* Annotation is only available in the source code. 在源文件中有效(指定注解只保留在源文件当中,编译成类文件后就把注解去掉;)
*/
SOURCE,
/**
* Annotation is available in the source code and in the class file, but not
* at runtime. This is the default policy. 在class文件中有效,不是在运行时有效(指定注解只保留在源文件和编译后的class 文件中,当jvm加载类时就把注解去掉)
*/
CLASS,
/**
* Annotation is available in the source code, the class file and is
* available at runtime. 运行时有效
*/
RUNTIME
}
二、解析绑定注解控件
public class BindUtils {
public static void initBindView(Object curClass, View sourceView){
// 通过反射获取到全部属性,反射的字段可能是一个类(静态)字段或实例字段
Field[] fields = curClass.getClass().getDeclaredFields();
if(fields != null && fields.length > 0){
BindView bindView = null;
for(Field field : fields){
//获取自定义的注解类标志
bindView = field.getAnnotation(BindView.class);
if(bindView != null){
int viewId = bindView.id();
boolean clickBoolean = bindView.click();
try {
//反射访问私有成员,必须加上这句
field.setAccessible(true);
if (clickBoolean) {
sourceView.findViewById(viewId).setOnClickListener(
(OnClickListener) curClass);
}
//将currentClass的field赋值为sourceView.findViewById(viewId)
//给我们要找的字段设置值
field.set(curClass, sourceView.findViewById(viewId));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
/**
* 必须在setContentView之后调用
*
* @param aty
*/
public static void initBindView(Activity aty) {
initBindView(aty, aty.getWindow().getDecorView());
}
}
三、使用
MainActivity.class
public class MainActivity extends Activity implements OnClickListener{
//R.id.btn得和xml里面的一致,否则无效
@BindView(id = R.id.btn, click = true)
private Button btn;
@BindView(id = R.id.tv)
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BindUtils.initBindView(this);//这里一定得放在setContentView()后
tv.setText("绑定成功...");
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn:
Log.i("TAG", "点击了....");
break;
default:
break;
}
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.bindviewdemo.MainActivity" >
<Button
android:id="@+id/btn"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="请点击我" />
<TextView
android:id="@+id/tv"
android:layout_below="@id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
点击buttom: