xUtils -- view模块分析

来源:互联网 发布:vue.js v bind的用法 编辑:程序博客网 时间:2024/05/22 00:18

简介

xUtils是Android的工具库,其中包含有View、Bitmap、Db、Http四个模块。

本篇主要争对xUtils的2.6.14版本和xUtils3版本的View模块做个分析。

View模块主要提供功能有View布局的绑定,事件的绑定。而在xUtils2.6.14中还提供资源绑定等功能。

使用

@ContentView(R.layout.activity_main)public class MainActivity extends Activity {    @ViewInject(R.id.btn)    Button btn;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        x.view().inject(this);    }    @Event(value = R.id.btn, type = View.OnLongClickListener.class)    private boolean onBtnClick(View view) {        Toast.makeText(MainActivity.this, "onBtnClick", Toast.LENGTH_SHORT).show();        return true;    }}

简要分析

主要通过注解,反射,动态代理的技术。

在定义View时添加注解,确定所要注入的id等信息,并在Activity启动的onCreate方法执行注入x.view().inject(this);,而对于事件的绑定则还需要通过动态代理来实现。

流程图

图片很好概括了这个过程,图片来自于xUtils 源码解析

关于注解的文章:
Java注解实践
公共技术点之 Java 注解 Annotation

关于反射的文章:
公共技术点之 Java反射 Reflection

关于动态代理的文章:
公共技术点之 Java 动态代理
Java 动态代理机制分析及扩展

xUtils2.6.14和xUtils3分析

两者都支持注解ContentView、View、Event。

但是2.6.14版本支持注解资源,还有preference,这些功能在xUtils3被移除掉。

xUtils2.6.14和xUtils3的View部分变化主要在Event部分,对比两个版本View模块注解,可以发现2.6.14版本的事件注解类型多,而且扩展性不高,

先看下xUtils2.6.14事件注解

// xUtils2.6.14@Target(ElementType.ANNOTATION_TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface EventBase {    Class<?> listenerType();    String listenerSetter();    String methodName();}// onClick方法注解 其他注解类似@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@EventBase(        listenerType = View.OnClickListener.class,        listenerSetter = "setOnClickListener",        methodName = "onClick")public @interface OnClick {    int[] value();    int[] parentId() default 0;}

再看下xUtils3的事件注解:

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Event {    /**     * 控件的id集合, id小于1时不执行ui事件绑定.     *     * @return     */    int[] value();    /**     * 控件的parent控件的id集合, 组合为(value[i], parentId[i] or 0).     *     * @return     */    int[] parentId() default 0;    /**     * 事件的listener, 默认为点击事件.     *     * @return     */    Class<?> type() default View.OnClickListener.class;    /**     * 事件的setter方法名, 默认为set+type#simpleName.     *     * @return     */    String setter() default "";    /**     * 如果type的接口类型提供多个方法, 需要使用此参数指定方法名.     *     * @return     */    String method() default "";}

xUtils3通过使用一个注解表示事件。

看下主要函数:

private static void injectObject(Object handler, ViewFinder finder) {        Class<?> handlerType = handler.getClass();        // inject ContentView        ContentView contentView = handlerType.getAnnotation(ContentView.class);        // ...        Method setContentViewMethod = handlerType.getMethod("setContentView", int.class);        setContentViewMethod.invoke(handler, contentView.value());        // ...          // inject view        Field[] fields = handlerType.getDeclaredFields();        if (fields != null && fields.length > 0) {            for (Field field : fields) {                ViewInject viewInject = field.getAnnotation(ViewInject.class);                if (viewInject != null) {                    try {                        View view = finder.findViewById(viewInject.value(), viewInject.parentId());                        if (view != null) {                            field.setAccessible(true);                            field.set(handler, view);                        }                    } catch (Throwable e) {                        LogUtils.e(e.getMessage(), e);                    }                } else {                    // inject resourse                    ResInject resInject = field.getAnnotation(ResInject.class);                    if (resInject != null) {                        try {                            Object res = ResLoader.loadRes(                                    resInject.type(), finder.getContext(), resInject.id());                            if (res != null) {                                field.setAccessible(true);                                field.set(handler, res);                            }                        } catch (Throwable e) {                            LogUtils.e(e.getMessage(), e);                        }                    } else {                        // inject preference                        // ...                        field.set(handler, preference);                        // ...                    }                }            }        }        // inject event        Method[] methods = handlerType.getDeclaredMethods();        if (methods != null && methods.length > 0) {            for (Method method : methods) {                Annotation[] annotations = method.getDeclaredAnnotations();                if (annotations != null && annotations.length > 0) {                    for (Annotation annotation : annotations) {                        Class<?> annType = annotation.annotationType();                        if (annType.getAnnotation(EventBase.class) != null) {                            method.setAccessible(true);                            try {                                // ...                                for (int i = 0; i < len; i++) {                                    ViewInjectInfo info = new ViewInjectInfo();                                    info.value = Array.get(values, i);                                    info.parentId = parentIdsLen > i ? (Integer) Array.get(parentIds, i) : 0;                  // 动态代理处理                  EventListenerManager.addEventMethod(finder, info, annotation, handler, method);                                }                            } catch (Throwable e) {                                LogUtils.e(e.getMessage(), e);                            }                        }                    }                }            }        }    }

而对于这一个过程分析及实现的有
打造IOC框架 上
打造IOC框架 下

总结

本篇博客简单分析xUtils的view注入过程,和对xUtils版本改进后的理解。

View的注入使用了注解和反射等技术,在开发过程中难免会造成资源浪费以及效率低下,但是这一过程涉及到Java的注解和反射以及动态代理等技术,还是非常值得去学习,而不是只会使用。

最后,如哪里不足或者分析错误,非常欢迎指正,谢谢。

1 0
原创粉丝点击