安卓进阶之自己实现 ViewInject框架

来源:互联网 发布:防御sql注入原理 编辑:程序博客网 时间:2024/05/17 02:58

以前做web开发的时候经常用得到的就是SSH框架,即struts2、spring、hibernate三大框架,他们分别负责了不同的层的业务逻辑,其中spring框架是我觉得最猛的一个框架,它几乎贯穿到整个web开发中,而它的特色功能就是IOC、AOP等,AOP是面向切面编程,根据动态代理技术来动态管理我们的java代码,功能非常强大。IOC是控制反转,为什么叫控制反转呢?因为我们一般实例化一个对象都是自己手动通过new来实现,而spring通过自己的IOC技术就可以通过配置或者注解的方法来帮助我们new一个对象,使我们不用关注实例化对象的方法,从而注重程序的业务逻辑,在一方面也能达到很好的解耦作用。
现在安卓中也引入了IOC技术,可以在网上下载到ViewInject项目来使用我们的IOC功能,于是我们又多了一个新技能,使用别人写的ViewInject框架。程序员中有一句话叫做不要重复的制造轮子,我们大多数程序员都是拿来主义,只要功能实现就行,而不去管其中的原理,不自己是考虑一下怎么实现的,但叫自己做的话能不能实现呢?于是我决定动手实现ViewInject框架,虽然比较简陋,但是自己的东西写出来才是硬道理哇。


要实现ViewInject框架需要了解一下java中反射的概念,所谓反射其实就是通过非new的方式来获取我们的属性、方法等内容,同时也可以通过反射来实例化一个对象,功能非常强大,是设计框架的必备良药。通过几个例子来说明:

//有一个A类,我们传统的可以通过new A来获取对象,并且调用里面的方法或者属性//主要有一个name属性,它是私有的,如果通过new的方法还能调用吗?class A {    private int age = 100;    private String name = "私有属性";    public void sayHellow() {        System.out.println("你好");    }}//如果需要调用里面的私有属性或者私有方法,则需要通过法神来实现:public static void main(String[] args) throws Exception {        Class<A> clazz = A.class;        // 实例化一个A对象        A a = clazz.newInstance();        // 获取所有的属性(包括私有属性),也可以使用getFields方法,但是这样不能        // 获取到私有属性        Field[] fileds = clazz.getDeclaredFields();        for (Field f : fileds) {            // 如果需要访问私有属性,这里必须要设置为true            f.setAccessible(true);            System.out.println(f.get(a));        }        // 获取所有的方法(包括私有方法),也可以使用getMethods方法,但是这样不能        // 获取到私有方法        Method[] methods = clazz.getDeclaredMethods();        for (Method m : methods) {            // 如果需要访问私有方法,这里必须要设置为true            m.setAccessible(true);            m.invoke(a, null);        }    }    打印结果:    100    私有属性    你好

可以看到通过反射能够正常访问私有属性,私有方法等,非常厉害!
我们在整合SSH框架的时候有时候为了简化经常使用注解的方式,注解英文名幼教Annotation,非常好用,用法也很简单,这里略过。。。
下面就是实现自己的ViewInject框架了
首先看一下我们使用自己的框架的代码:

@ContentView(R.layout.activity_main)//这里使用了注解public class MainActivity extends Activity {    @ViewInject(R.id.tv1)//这里使用了注解    private TextView tv;    @ViewInject(R.id.btn1)//这里使用了注解    private Button btn;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ViewUtil.inject(this);//自定义的工具类        tv.setText("通过自定义矿建实现的");    }    @OnClick({ R.id.btn1, R.id.btn2 })//这里使用了注解    public void btn(View view) {        switch (view.getId()) {        case R.id.btn1:            Toast.makeText(getApplicationContext(), "点击了按钮1",                    Toast.LENGTH_SHORT).show();            break;        case R.id.btn2:            Toast.makeText(getApplicationContext(), "点击了按钮2",                    Toast.LENGTH_SHORT).show();            break;        }    }}

可以看到我们总共有三个注解类型:ContentView、ViewInject、OnClick以及一个ViewUtil工具类
首先定义自己的ContentView注解类型:

//运行环境,此处是运行时@Retention(RetentionPolicy.RUNTIME)// 此处表示注解可以存放的位置,此处设置为在类上@Target(ElementType.TYPE)public @interface ContentView {    int value();}

定义ViewInject类型:

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface ViewInject {    int value();}

定义OnClick类型:

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface OnClick {    //此处返回一个数据表示可以通过定义多个    int[] value();}

最后使我们的核心控制类:

/** * 核心控制类 *  * @author leilu *  */public class ViewUtil {    /**     * 开始注解     *      * @param activity     */    public static void inject(Activity activity) {        // 判断对应的Activity上面是否使用了ContentView注解        if (activity.getClass().isAnnotationPresent(ContentView.class)) {            // 如果加了注解则转换为ContentView注解            ContentView contentView = activity.getClass().getAnnotation(                    ContentView.class);            int layoutResID = contentView.value();// 获取布局的资源id            activity.setContentView(layoutResID);// 设置布局内容            findView(activity);// 绑定view            registEvent(activity);// 注册点击事件        }    }    /**     * 注册点击事件     *      * @param activity     */    private static void registEvent(final Activity activity) {        // 获取所有的方法        Method[] method = activity.getClass().getMethods();        for (final Method m : method) {            // 判断方法上面使用存在OnClick注解            if (m.isAnnotationPresent(OnClick.class)) {                // 如果存在则转换                OnClick on = m.getAnnotation(OnClick.class);                int[] values = on.value();// 获取需要绑定点击事件的控件id                for (int i = 0; i < values.length; i++) {                    final View view = activity.findViewById(values[i]);                    // 给其设置点击事件                    view.setOnClickListener(new OnClickListener() {                        @Override                        public void onClick(View v) {                            try {                                m.invoke(activity, view);// 调用activity里面的方法                            } catch (Exception e) {                                e.printStackTrace();                            }                        }                    });                }            }        }    }    /**     * 绑定view控件     *      * @param activity     */    private static void findView(Activity activity) {        // 获取所有属性        Field[] fields = activity.getClass().getDeclaredFields();        for (Field field : fields) {            field.setAccessible(true);            // 判断属性上面是否存在ViewInject注解            if (field.isAnnotationPresent(ViewInject.class)) {                ViewInject vi = field.getAnnotation(ViewInject.class);                int resourceId = vi.value();// 获取控件资源id                try {                    field.set(activity, activity.findViewById(resourceId));// 绑定控件                } catch (IllegalArgumentException e) {                    e.printStackTrace();                } catch (IllegalAccessException e) {                    e.printStackTrace();                }            }        }    }}

OK,自定义框架实现完毕!看看效果:
这里写图片描述

0 0
原创粉丝点击