分享

Android注解(annotation)实现绑定事件的原理

 quasiceo 2014-09-09
Android注解(annotation)实现绑定事件的原理
2014-08-31     我来说两句    来源:tangjiean的专栏  
收藏    我要投稿

注解是一种很优雅的书写方式,也是我们的代码变的简洁,更加快捷方便编写代码。下面以绑定onclick实践为例阐述注解的原理。

1、定义Onclick注解类

1
2
3
4
5
6
7
8
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@BaseEvent(listenerSetter = "setOnclickListener",
           listenerType = View.OnClickListener.class,
           methodName = "onclick")
public @interface OnClick {
     int[] values();
}

BaseEvent用来制定需要绑定的方法名,事件的Listener,和绑定执行的方法名,BaseEvent的代码如下

1
2
3
4
5
6
7
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BaseEvent {
    Class<!--?--> listenerType();
    String listenerSetter();
    String methodName();
}

2、自定义的注解使用方式

1
2
@OnClick(R.id.download_btn)
public void testUpload(View view) {}

3、注解的解析(重点):

思路:可以通过我们的注解对象中取得添加onclick注解的方法(testUpload)反射方法对象,对这个对象进行事件的绑定。动态代理View事件中的OnclickLister,向代理对象中添加方法对象(testUpload)。方法的添加在EventListenerManager管理类中完成。

EventLisernerManager中定义动态代理类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public static void addEventMethod(Method method,
        Annotation annotation,
        Object value,
        Object handler,
        ViewFinder finder){
    try{
        View view = finder.findViewByInfo(value);
        if(view!=null){
            BaseEvent baseEvent = annotation.annotationType().getAnnotation(BaseEvent.class);
            Class<!--?--> listenerType = baseEvent.listenerType();
            String listenerSetter = baseEvent.listenerSetter();
            String methodName = baseEvent.methodName();
             
            Object listener = listenerCache.get(value, listenerType);
            boolean addMethod =  false;
            DynamicHandler dymicHandler = null;
            if(listener!=null){
                dymicHandler = (DynamicHandler) Proxy.getInvocationHandler(listener);
                addMethod = (handler.equals(dymicHandler.getHandler()));
                if(addMethod){
                    dymicHandler.addMethod(methodName, method);
                }
            }
             
            if(!addMethod){
                dymicHandler = new DynamicHandler(handler);
                dymicHandler.addMethod(methodName, method);
                listener = Proxy.newProxyInstance(listenerType.getClassLoader(),
                           new Class<!--?-->[]{listenerType},dymicHandler);
                listenerCache.put(value, listenerType, listener);
            }
            //setListener
            Method setterMethod = view.getClass().getMethod(listenerSetter, listenerType);
            setterMethod.invoke(view, listener);
        }
    }catch(Exception e){
        LogUtils.e(e.getMessage(),e);
    }
}
listener = Proxy.newProxyInstance(listenerType.getClassLoader(),new Class[]{listenerType},dymicHandler);动态的代理了onClickListener。类中对代理对象进行的缓存:
1
2
3
//缓存代理对象
public final static DoubleKeyValueMap<object,class<?>, Object> listenerCache = null;
</object,class<?>


解析注解添加方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        Method[] methods = handlerType.getDeclaredMethods();
        if(methods.length>0){
            for(Method method:methods){
                Annotation[] annotations = method.getDeclaredAnnotations();
                for(Annotation annotation : annotations){
                    Class<!--?--> anType = annotation.annotationType();//拿到Annotation的Class
                    if(anType.getAnnotation(BaseEvent.class)!=null){
                        method.setAccessible(true);
                        try{
                        Method valueMethod = anType.getDeclaredMethod("values");
                        Object values = valueMethod.invoke(annotation);
                        int len = Array.getLength(values);
                        if(len>0){
                            for(int i=0;i<len;i++){ object="" value="Array.get(values," i);="" eventlistenermanager.addeventmethod(method,="" annotation,="" value,="" handlertype,="" finder);="" }="" }catch(exception="" e){="" e.printstacktrace();="" }<="" pre="">        这里可以拿到自定义method和注解本身。不太了解的可以研究下java的annotation的用法。<p></p>
<p>由以上的方法的可以实现注解事件的绑定,可以自己定义事件的注解,优雅的开始你的代码吧!</p>
<p><br>
</p>
<p><br>
</p>
<p><br>
<br>
</p>
<br>
<p><br>
</p>
<p><br>
<br>
</p>
<br>
<p><br>
</p>                        </len;i++){>

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多