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);            }        });    }}

注解的使用可以让我们的代码更加简洁,但前提是,这种前提是否有必要。

更多相关文章

  1. 第一章:第一行android代码注解(4)
  2. Android:xUtils3 浅析(二)——数据库模块
  3. Android(安卓)Room 框架学习
  4. Android(安卓)JS交互与JS代码注入--详解
  5. 【Android(安卓)Developers Training】 13. 支持不同平台版本
  6. Android(安卓)Studio插件-Android(安卓)Butterknife Zelezny
  7. Android(安卓)Contact分析(一):Data, RawContact, Contact之间的关
  8. Android之sqlite3命令行简单使用
  9. AndroidStudio使用偷懒插件Butterknife和GsonFormat 编辑

随机推荐

  1. ListView@常用属性记录
  2. Android Toast&Notification(Part I)
  3. 一个封装好的Android仿Ios ActionSheet控
  4. android构建自定义的视图组件
  5. Android音量调节原理
  6. Android使用第三方SDK——百度地图
  7. Android图形子系统
  8. Android(安卓)WebView 实现JS相互调用 Js
  9. android 闹钟的实现
  10. 理解Android UI与线程交互