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

42 篇文章 0 订阅
3 篇文章 0 订阅

前言

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与控件的绑定,这就是注入框架主要的精髓了,需要更好更强大的框架还需要自己慢慢完成。这里贴上源代码地址:传送门

本项目是一个基于安卓的框架项目源码 Loonandroid是一个注解框架,不涉及任何UI效果,目的是一个功能一个方法,以方法为最小颗粒度对功能进行拆解。把功能傻瓜化,简单化,去掉重复性的代码,隐藏复杂的实现。以便团队合作或者后期修改变得简单。说框架是夸大了,主要是因为我比较喜欢偷懒,对于一个码农来说,能够偷懒,并且在不影响项目质量的情况下,是不容易的。 很多朋友看到注解就就要吐槽,会影响性能什么的。注解,确实会影响性能。通过注解自动注入,反射会让程序变慢50~100毫秒左右,从体验感基本感觉不出来.硬件性能好的手机可以忽略,经过测试无需太大的担心。我是做外包的,初衷是在不影响项目质量的前提下减少我的工作量,而且BUG其他人改起来相对比较容易,本工具专属外包码农,如果你想做精细,很在意性能数据,请看看就好。 1、基本功能 InLayer注解 InPlayer 注解 Activity生命周期注解 InView注解 InSource注解 InAll注解 后台进程注解 方法点击事件注解 基类注解 自动Fragment注解 手动Fragment注解 2、适配器功能 无适配器 无参baseAdapter 自定义一adapter 自定义二adapter 自动绑定一adapter 自动绑定二adapter 通用适配器 3、综合功能集合 网络请求模块 输入验证 跨进程通讯 Json格式化类 倒计时类 4、傻瓜式下拉刷新 Listview Grid 横向Scrollview 纵向Scrollview 横向ViewPage 纵向ViewPage WebView 5、自定义模块类 自定义模块XML中使用 自定义模块变量使用 6、傻瓜式组件类
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值