Android注解式绑定控件

Android开发中,有一个让人又爱又恨的方法叫findViewById(int);我想如果你是一民Android开发者,必然知道这个方法,让我们来看一下KJFrameForAndroid框架是如何解决这个问题的。

公司主营业务:成都做网站、网站建设、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。成都创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。成都创新互联推出农安免费做网站回馈大家。

KJFrameForAndroid框架项目地址:https://github.com/kymjs/KJFrameForAndroid。

为什么说findViewById(int);让人又爱又恨呢?想必大家也是很有感触。
写一个布局,用Java代码写和用xml文件写,完成速度完全是无法比拟的。xml布局太方便了。
同样的,想获取一个控件的对象,如果你是使用的xml布局文件写的布局,那么你必须调用findViewById()这个方法。

 
 
 
 
  1. TextView t = (TextView) findViewById(R.id.x); 

这是我们最常见的 获取xml布局中一个textview对象的过程。
那么问题就来了,这特么奇葩的方法名也太长了吧!!!好吧,其实人家名字起的也没有错,要描述清楚这函数的含义,也必须这么多个字母。
可是你丫的返回一个View让我用的时候还得强转,这也太麻烦了吧。我一行代码总共也就100列(Eclipse默认),缩进八格(方法写在类里面,语句写在方法里面),
就算像上面的例子textView对象只有一个字母,id也只有一个字母,这一个初始化也要占我54列了。要是变量名再长点,缩进层次再深点,这一个初始化就两行了。
一个界面至少也有四个控件吧,这么复杂的初始化,太坑爹了。
有问题总会有对应的解决办法,下面我就向大家介绍一下使用注解解决这种麻烦。
了解注解:

从jdk1.5开始,Java提供了注解的功能,允许开发者定义和使用自己的注解类型,该功能由一个定义注解类型的语法和描述一个注解声明的语法,读取注解的API,一个使用注解修饰的class文件和一个注解处理工具组成。
首先,你需要接受一个关键字@interface ,噢,它可不是接口定义关键字,更不是OC里面的@interface关键字,是Java中表示声明一个注解类的关键字。
使用@interface 表示我们已经继承了java.lang.annotation.Annotation类,这是一个注解的基类接口,就好像Object类,现在你只需要知道它的存在就行了。
还有一条规定:在定义注解时,不能继承其他的注解或接口。
那么,这就是最简单的一个注解类

 
 
 
 
  1. public @interface MyAnnotation { 
  2.   

然而通常在使用时我们都会给这个注解类加上两个注解:

@Target(ElementType.FIELD)、@Retention(RetentionPolicy.RUNTIME)
ElementType、RetentionPolicy是两个枚举类,ElementType.FIELD表示我们需要注解的是一个字段,以下是摘自JDK1.6文档中的介绍:

使用注解:

以下为KJFrameForAndroid框架中绑定控件注解部分的定义与使用

 
 
 
 
  1. @Target(ElementType.FIELD) 
  2. @Retention(RetentionPolicy.RUNTIME) 
  3. public @interface BindView { 
  4.     public int id(); 
  5.     public boolean click() default false; 
  6. }
  7. @BindView(id = R.id.x, click = true) 
  8. private TextView t; 

我们可以看到,除了明显减少了代码量,还使得代码结构更加清晰。
其中,定义部分的id() 表示注解接受一个int类型的数据作为id所对应的值(就如使用中的id = R.id.xxx);
同理,定义部分的click表示接受一个Boolean类型的数据作为click对应的值,还可以设置一个默认值使用default修饰;
处理注解:

我们已经知道了注解怎么定义和使用,接下来就应该知道怎么处理了。
上面已经说了,bindview注解可以接受一个int类型的值和一个Boolean类型的值,那么这两个值接受了以后如何获取呢?
其实获取的方式很简单就是通过一个BindView类型的对象,调用这个对象来自声明中定义的两个方法——>id()或click()方法。
现在就有一个问题了,注解类型是不能直接new对象的,那么这个BindView对象从哪里来呢?
这时就需要用到Java的反射机制。我们知道,每一个继承自Object类的类都会继承一个getClass()方法,下面看一下这个方法的原型:

 
 
 
 
  1. /** 
  2.     * Returns the unique instance of {@link Class} that represents this 
  3.     * object's class. Note that {@code getClass()} is a special case in that it 
  4.     * actually returns {@code Class} where {@code Foo} is the 
  5.     * erasure of the type of the expression {@code getClass()} was called upon. 
  6.     * 

     

  7.     * As an example, the following code actually compiles, although one might 
  8.     * think it shouldn't: 
  9.     * 

     

  10.     * 
    {@code 
  11.     *   List l = new ArrayList(); 
  12.     *   Class c = l.getClass();}
 
  •     * 
  •     * @return this object's {@code Class} instance. 
  •     */ 
  •    public final native Class getClass(); 
  • 是一个native方法,根据注释我们知道,这个方法返回的是该类的Class对象,同时也是该类的二进制对象。
    Class中有一个方法叫getDeclaredFields(),是用来返回这个类的全部字段,返回类型是Field[]
    通过Field对象的getAnnotation(Class)方法,我们可以获取到任何一个Class的对象,通过getAnnotation(Class),我们就可以获取到BindView的对象了。

    例如

     
     
     
     
    1. Field[] fields = currentClass.getClass().getDeclaredFields(); 
    2. for(int i = 0; i < fields.length; i++){ 
    3.   
    4.     BindView bindView = field.getAnnotation(BindView.class); 
    5.       
    6.     int viewId = bindView.id();  //这是我们传的id 
    7.       
    8.     boolean clickLis = bindView.click(); //这是我们传的click 

    在Android项目中应用:

    至此,我们已经了解了注解,并且知道怎么使用,怎么处理注解了,现在只剩下最后一个问题:在项目中使用。
    很简单,传一个Activity对象,调用findViewById()不就行了。
    于是,我们可以这样
    activity.findViewById( bindView.id() );
    最后在我们的Activity中调用这个函数就OK了。

    以下是Android应用框架KJFrameForAndroid中使用注解绑定控件的核心代码:

     
     
     
     
    1. /** 
    2.      * @param currentClass 
    3.      *            当前类,一般为Activity或Fragment 
    4.      * @param sourceView 
    5.      *            待绑定控件的直接或间接父控件 
    6.      */ 
    7.     public static void initBindView(Object currentClass, View sourceView) { 
    8.         // 通过反射获取到全部属性,反射的字段可能是一个类(静态)字段或实例字段 
    9.         Field[] fields = currentClass.getClass().getDeclaredFields(); 
    10.         if (fields != null && fields.length > 0) { 
    11.             for (Field field : fields) { 
    12.                 // 返回BindView类型的注解内容 
    13.                 BindView bindView = field.getAnnotation(BindView.class); 
    14.                 if (bindView != null) { 
    15.                     int viewId = bindView.id(); 
    16.                     boolean clickLis = bindView.click(); 
    17.                     try { 
    18.                         field.setAccessible(true); 
    19.                         if (clickLis) { 
    20.                             sourceView.findViewById(viewId).setOnClickListener( 
    21.                                     (OnClickListener) currentClass); 
    22.                         } 
    23.                         // 将currentClass的field赋值为sourceView.findViewById(viewId) 
    24.                         field.set(currentClass, sourceView.findViewById(viewId)); 
    25.                     } catch (Exception e) { 
    26.                         e.printStackTrace(); 
    27.                     } 
    28.                 } 
    29.             } 
    30.         } 
    31.     } 

    其实安卓中的注解式绑定控件(也是所谓的IOC控制反转在安卓中的一种应用)其实本质的使用就是Java基础中反射的使用。值得一提的是,反射执行的效率是很低的
    如果不是必要,应当尽量减少反射的使用,因为它会大大拖累你应用的执行效率。
    顺带一提:我一直很排斥注解,因为类反射的效率太低了。现在有很多安卓应用开发框架,比如KJFrameForAndroid, xUtils, afinal, thinkAndroid,这些框架都是使用反射来起到注解绑定控件。
    更有的框架甚至是一切东西都使用注解去完成,我只能说注解便捷,但请慎用。

    本文链接:http://my.oschina.net/kymjs/blog/305882

    分享题目:Android注解式绑定控件
    文章网址:http://www.mswzjz.cn/qtweb/news1/250101.html

    攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能