打造Android依赖注入框架,改变你的代码方式(上)

先来介绍下本次列车

本次列车来自地球,时速200km/s,即将开往火星,请要上车的朋友速速上车..
先介绍一个非常重要的东西:注解
注解(Annotation),我们在写代码的过程中,相信已经见不少了

举个栗子

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

简单一点来说就是带有@标记加上关键字的,我们通称为注解.
引用一下装逼语句

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

能够添加到 Java 源代码的语法元数据。类、方法、变量、参数、包都可以被注解,可用来将信息元数据与程序元素进行关联。Annotation 中文常译为“注解”。

注解的作用

  • 标记,用于告诉编辑器信息

  • 编译时动态处理,用于动态生成代码

  • 运行时动态处理,用于得到注解信息

定义注解
package com.eicky;

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Person {
    String name() default "";
    String sex() default ""; 
}

注解是通过 @interface 定义, 注解名则为你定义的名字.
实现部分所有方法没有方法体,没有参数没有修饰符,实际只允许 publicabstract 修饰符,默认为 public,不允许抛异常.
方法返回值只能是基本类型,String, Class, annotation, enumeration 或者是他们的一维数组.

@Target:定义注解的作用目标

  • @Target(ElementType.TYPE) //接口、类、枚举、注解
  • @Target(ElementType.FIELD) //字段、枚举的常量
  • @Target(ElementType.METHOD) //方法
  • @Target(ElementType.PARAMETER) //方法参数
  • @Target(ElementType.CONSTRUCTOR) //构造函数
  • @Target(ElementType.LOCAL_VARIABLE)//局部变量
  • @Target(ElementType.ANNOTATION_TYPE)//注解
  • @Target(ElementType.PACKAGE) ///包

@Retention: 定义注解的保留策略

  • @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
  • @Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
  • @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
调用注解
package com.eicky;

public class Eicky {
    @Person(name = "eicky", sex = "男")
    public String getInfo() {
        return "Hello, Eicky";
    }
}
解析注解

可以手动调用下面三个常用API进行解析

target.getAnnotation(AnnotationName.class);
target.getAnnotations();
target.isAnnotationPresent(AnnotationName.class);

好了,介绍了我们最重要的东西,应该步入正题了
我们Android中其实已经用过很多的依赖注入框架了,比如xutils、Retrofit 、Butter Knife、ORMLite等等,这些都是Android中的依赖注入框架,下面我们自己动手打造一个简单的依赖注入(毕竟一两篇博客是不可能做一个完美的依赖注入框架的)

不扯犊子了,发车了..

注入ContentView

  • 定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
    int value();
}
  • 使用注解
@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
    ....
}

注入View

  • 定义注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
    int value();
}
  • 使用注解
@ViewInject(R.id.text)
TextView mTextView;

解析定义的注解,并且注入到Activity中

定义InjectUtils

public class InjectUtils {
    private static final String CONTENT_VIEW_METHOD = "setContentView";
    private static final String FIND_VIEW_METHOD = "findViewById";

    public static void inject(Activity activity){
        injectContentView(activity);
        injectViews(activity);
    }
    //注入ContentView
    private static void injectContentView(Activity activity){
        Class<? extends Activity> clazz = activity.getClass();
        //获取Class上的ContentView注解
        ContentView contentView = clazz.getAnnotation(ContentView.class);
        if (contentView != null){
            try {
                Method method = clazz.getMethod(CONTENT_VIEW_METHOD, int.class);
                //反射调用Activity的setContentView方法
                method.invoke(activity, contentView.value());
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    //注入View
    private static void injectViews(Activity activity){
        Class<? extends Activity> clazz = activity.getClass();
        //获取Activity中所有的字段
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields){
            //获取字段上带有ViewInject标记的字段
            ViewInject viewInject = field.getAnnotation(ViewInject.class);
            if (viewInject != null){
                try {
                    Method method = clazz.getMethod(FIND_VIEW_METHOD, int.class);
                    //反射调用Activity的findViewById方法获取View对象
                    Object target = method.invoke(activity, viewInject.value());
                    field.setAccessible(true);
                    //对字段设值
                    field.set(activity, target);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这样就完成了我们简单的ContentView视图和View的注入


下一篇将带大家进行Android中事件的注入,代码已上传github, 传送门

本项目是一个基于安卓框架项目源码 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、付费专栏及课程。

余额充值