Android注入框架你应该知道的一切------打造自己的注入框架

前言

Java的所有框架基本都是基于反射的,所以有句话是这么说的,无反射,无框架。所以Android的注入框架也是基于反射的,接下来就简单的介绍一下Android的注入框架你应该知道的一切。

注解简介

注解(Annotation)在Java里面是比较重要的一部分,但是通常很少接触到这一部分,这里就简单的过一下。现在我们简单的写一个注解然后解释它。

通过Eclipse右键->New->Annotation然后敲入下面的代码。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation
{
    int vauls();
    String test();
}

可以看到Target这个标注我们定义为FIELD就是类里面的属性的意思,Retention这个标注是表示是运行时的注解。每个注解的意思大家可以收一下自己看看。然后看看我们怎么使用这个注解。我们随便在某一个类里面声明一个对象。如下

    @TestAnnotation(test="hello",vauls=12)
    private Button button3;

这样就声明好了我们的注解。然后就是注解的使用。也简单的看一下怎么使用的。

    Class<?> clas = getClass();
        //获取属性
        Field fields[] = clas.getDeclaredFields();
        for (Field field : fields)
        {
            //获取注解
            TestAnnotation testAnnotation = field.getAnnotation(TestAnnotation.class);
            if (testAnnotation != null)
            {
                //得到注解里面的值
                String test = testAnnotation.test();
                int id = testAnnotation.vauls();
                System.out.println(test + id);
            }
        }

就这样简单的使用,如果需要深入的理解注解可以在查一下注解的资料。

关于注入框架你应该知道的一切

打造自己的注入框架

首先说一下我们这次要实现怎么样的一个东西,注入View和注入Onclick事件,首先我们先解决注入View的问题.

View的注入

首先我们还是新建一个注解,敲入以下代码。

package com.edsheng.inject;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/***
 * Copyright (c) 2015, TNT All Rights Reserved.
 * View注解在声明VIew控件的时候进行注解就行了
 * @author bobo
 * @date 2015-6-9
 * @filename ViewInject.java
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject
{
    int value();
}

然后我们在新建一个ViewInjectUtile类,在里面实现这样的一个方法。

/***
     * 注入控件View
     * 简单说一下注入控件的流程
     * 1:根据Filed遍历所有的Filed
     * 2:得到我们需要的注解
     * 3:根据注解拿到id
     * 4:通过反射去调用找查方法
     * 5:最后通过反射赋值
     *
     * @param activity
     */
    private static void injectView(Activity activity)
    {
        Class<?> cls = activity.getClass();
        Field field[] = cls.getDeclaredFields();// 获取所有的filed
        for (Field field2 : field)
        {
            ViewInject inject = field2.getAnnotation(ViewInject.class);// 获取注解
            if (inject != null)
            {
                int id = inject.value(); // 得到id
                try
                {
                    // findViewById
                    Method method = cls.getMethod("findViewById", int.class);
                    Object resView = method.invoke(activity, id);// 得到控件
                    field2.setAccessible(true);
                    field2.set(activity, resView);// 赋值给View
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }

            }
        }

    }

注释都写的很清楚我就不解释了,这样就很简单的实现了View的注入,使用也很简单。

事件的注入

我们还是新建一个注解来完成我们的事件注入,敲入以下代码。

/***
 *
 * Copyright (c) 2015, TNT All Rights Reserved.
 * 方法的注解类在需要回调OnlickLisenler的时候进行注解就行了
 *
 * @author bobo
 * @date 2015-6-9
 * @filename MethodInject.java
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInject
{
    int[] value();
}

然后在ViewInjectUtile这个类里面实现这样一个方法。

/**
     * 注入监听的方法 所有的框架基本都是基于反射来实现的,不是有一句话么?无反射无框架。
     * 简单的说一下这个流程
     * 1:在我们的acitvity里面注入方法
     * 2:生成动态代理
     * 3:通过东动态代理去回调我们注入的方法
     *
     * @param activity
     */
    private static void injectMethod(Activity activity)
    {
        Class<?> cls = activity.getClass();
        Method methods[] = cls.getMethods();// 获取这个类的public方法
        for (Method method : methods)
        {
            MethodInject meathdInject = method.getAnnotation(MethodInject.class); // 获取方法上的注解
            if (meathdInject != null)
            {// 当有注解的时候生成动态代理
                Object proxy = (Object) Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(), new Class<?>[] { View.OnClickListener.class }, new DynaHanlder(activity, method));
                int ids[] = meathdInject.value();// 获取注解里面的id
                try
                {

                    Method findviewbyid = cls.getMethod("findViewById", int.class);// 得到方法
                    for (int id : ids)
                    {
                        Object view = findviewbyid.invoke(activity, id);// 根据方法获取view
                        Method onclickMethod = view.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
                        onclickMethod.invoke(view, proxy);// 调用setOnClickListener方法回调在动态类里面
                    }
                }

                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }

        }
    }

这里需要注意的就是动态类的生成和代理,我们把View.OnClickListener这个的接口通过代理和反射来回调给注解的地方,我们来看看这个DynaHanlder怎么实现的。

public static class DynaHanlder implements InvocationHandler
    {
        Object target = null;
        Method method = null;

        public DynaHanlder(Object target, Method method)
        {
            super();
            this.target = target;
            this.method = method;
        }

        /**
         * 这个函数就是动态注册的回调方法
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
        {
            // 这里调用动注入的方法
            return this.method.invoke(target, args);
        }

    }

也很简单就是保持我们的方法的应用当通过代理回调我们的时候我们也通过反射去调用我们的方法。

最后再给外部暴露一个接口方法。

//外部调用接口
static public void inject(Activity activity)
    {
        injectView(activity);
        injectMethod(activity);
    }

最后来看看我们怎么使用它吧。

public class MainActivity extends Activity
{

    @ViewInject(R.id.button)
    private Button button;
    @ViewInject(R.id.button2)
    private Button button2;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mainactivity);
        ViewInjectUtile.inject(this);
        button.setText("fuck");
        button2.setText("asdfasdf");
    }

    @MethodInject({ R.id.button, R.id.button2 })
    public void onClick(View v)
    {
        switch (v.getId())
        {
        case R.id.button:
            // System.out.println("asdfasdf");
            Toast.makeText(this, "R.id.button", 0).show();
            break;
        case R.id.button2:

            Toast.makeText(this, "R.id.button2", 0).show();
            // System.out.println("asdf");
            break;
        default:
            break;
        }
    }

当点击按钮会回调我们的方法,注入一开始就帮我们完成了id与控件的绑定,这就是注入框架主要的精髓了,需要更好更强大的框架还需要自己慢慢完成。这里贴上源代码地址:传送门

时间: 2024-08-03 23:39:17

Android注入框架你应该知道的一切------打造自己的注入框架的相关文章

Android注入框架你应该知道的一切——打造自己的注入框架

Java的所有框架基本都是基于反射的,所以有句话是这么说的,无反射,无框架.所以Android的注入框架也是基于反射的,接下来就简单的介绍一下Android的注入框架你应该知道的一切. 注解简介 注解(Annotation)在Java里面是比较重要的一部分,但是通常很少接触到这一部分,这里就简单的过一下.现在我们简单的写一个注解然后解释它. 通过Eclipse右键->New->Annotation然后敲入下面的代码. @Target(ElementType.FIELD) @Retention(

Spring框架笔记(三)——Spring容器、属性注入和构造器注入详解

Spring 容器 在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用. Spring 提供了两种类型的 IOC 容器实现. BeanFactory: IOC 容器的基本实现. ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口. BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身: Appli

android课程表控件、悬浮窗、Todo应用、MVP框架、Kotlin完整项目源码

Android精选源码 Android游戏2048 MVP Kotlin项目(RxJava+Rerotfit+OkHttp+Glide) Android基于自定义Span的富文本编辑器 android课程表控件效果源码 Dagger.Clean.MVP框架搭建,快速开发- Andorid 任意界面悬浮窗,实现悬浮窗如此简单 android模仿QQ登录后保存账号和密码效果源码 Android简洁清爽的Todo清单工具(MVP+okhttp3+retrofit+gson) Android优质博客 K

【课程分享】jQuery2.0应用开发:SSH框架整合jQuery2.0实战OA办公自动化(VSS、operamasks-UI框架)

我的qq是2059055336,对这个课程有兴趣的可以加我qq联系. 课程下载地址:链接:http://pan.baidu.com/share/link?shareid=395438909&uk=3611155194 密码:mlvl 课程下载地址:http://www.kuaipan.cn/file/id_192202874577496484.htm?source=1 一.本课程是怎么样的一门课程(全面介绍)    1.1.课程的背景 jQuery 2.0 正式版发布,不在支持 IE 6/7/8

java SSH框架 SSM框架 SSI框架 源码 Java全新高大尚HTML5 bootstrap后台框架源码

获取[下载地址 (劳动所得,不喜勿喷)] [免费支持更新]A 代码生成器(开发利器);全部是源码     增删改查的处理类,service层,mybatis的xml,SQL( mysql   和oracle)脚本,   jsp页面 都生成   就不用写搬砖的代码了,生成的放到项目里,可以直接运行B 阿里巴巴数据库连接池druid;  数据库连接池  阿里巴巴的 druid.Druid在监控.可扩展性.稳定性和性能方面都有明显的优势C 安全权限框架shiro ;  Shiro 是一个用 Java

LrcCache和DiskLruCache相结合打造图片加载框架

LrcCache和DiskLruCache相结合打造图片加载框架 1概述 这几在研究图片加载的方面的知识,在网上看了一下前辈们写的文章,受到了一些启发,于是综合多方面的知识,将这些整合起来,自己边写了一个图片加载框架.说到图片加载最容易出问题的就是OOM就是内存溢出,所以一定要限制加载图片时使用的内存,这就使用到Android提供的缓存类LruCache,关于LruCache的知识这里不再赘述,大家自行学习.但是如果图片非常的多而且频繁操作的话,加上LruCache的缓存空间有限,缓存就不得不经

java SSM框架 多数据源 代码生成器 websocket即时通讯 shiro redis 后台框架源码

获取[下载地址]   QQ: 313596790官网 http://www.fhadmin.org/A 调用摄像头拍照,自定义裁剪编辑头像,头像图片色度调节B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,快速开发利器)+快速表单构建器 freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块C 集成阿里巴巴数据库连接池druid  数据库连接池  阿里巴巴的 druid.Druid在监控.可扩展性.稳定性和性能方面都

Android高级控件(五)——如何打造一个企业级应用对话列表,以QQ,微信为例

Android高级控件(五)--如何打造一个企业级应用对话列表,以QQ,微信为例 看标题这么高大上,实际上,还是运用我么拿到listview去扩展,我们讲什么呢,就是研究一下QQ,微信的这种对话列表,我们先看一个传统的ListView是怎么样的,我们做一个通讯录吧,通讯录的组成就是一个头像,一个名字,一个电话号码,一个点击拨打的按钮,既然这样,那我们的item就出来了 call_list_item.xml <?xml version="1.0" encoding="ut

java SSM 框架 多数据源 代码生成器 websocket即时通讯 shiro redis 后台框架源码

A 调用摄像头拍照,自定义裁剪编辑头像 [新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统]B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单;  技术:313596790 freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块C 集成阿里巴巴数据库连接池druid; 获取[下载地址]      数据库连接池  阿里巴巴的 druid.Druid在监控.可扩展性.稳定性和性能方面