【Android】Android 实现一个依赖注入的注解

Android 实现一个依赖注入的注解

🎯 目标功能

  • 自定义注解 @Inject
  • 创建一个 Injector 类,用来扫描并注入对象
  • 支持 Activity 或其他类中的字段注入

🧩 步骤一:定义注解

java 复制代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
}

🧩 步骤二:实现注入逻辑

java 复制代码
import java.lang.reflect.Field;

public class Injector {

    public static void inject(Object target) {
        Class<?> clazz = target.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(Inject.class)) {
                try {
                    Class<?> type = field.getType();
                    Object instance = type.newInstance(); // 也可以用构造器缓存池优化
                    field.setAccessible(true);
                    field.set(target, instance);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException("Failed to inject " + field.getName());
                }
            }
        }
    }
}

🧩 步骤三:使用示例

要实例化的对象类

java 复制代码
import android.util.Log;

public class Service {
    public void doSomething() {
        System.out.println("Service is working");
        Log.i("ServiceTAG", "Service is doSomething");
    }
}

在MainActivity注入

Java 复制代码
public class MainActivity extends AppCompatActivity {

    @Inject
    Service service;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 注入逻辑
        Injector.inject(this); 
        // 使用注入的对象
        service.doSomething(); 
    }
}

✅ 补充建议

  • 为了更灵活,你可以改用 构造器注入单例管理
  • 如果要支持参数构造函数、依赖图、作用域管理,可以逐步扩展。
  • 如果你对性能敏感,可以考虑使用 APT(注解处理器) 生成代码。

逐段解释一下上述代码:

🔧 一、自定义注解 @Inject

Java 复制代码
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
}
✅ 解读:
  • @Target(ElementType.FIELD)
    表示这个注解只能用于 字段上,不能用于类、方法等。
  • @Retention(RetentionPolicy.RUNTIME)
    表示这个注解在 运行时依然存在,这样我们就可以通过反射获取它。
  • public @interface Inject {}
    这是定义了一个名为 Inject 的注解,它 不包含任何参数,只作为标记使用。

🧠 二、注入器类 Injector

复制代码
public class Injector {

    public static void inject(Object target) {
        Class<?> clazz = target.getClass();
        Field[] fields = clazz.getDeclaredFields();
✅ 解读:
  • inject(Object target):这是一个静态方法,接收需要注入依赖的对象,比如 Activity
  • target.getClass():获取目标类的 Class 对象。
  • clazz.getDeclaredFields():获取这个类里 声明的所有字段(不管是私有还是公有)。
Java 复制代码
        for (Field field : fields) {
            if (field.isAnnotationPresent(Inject.class)) {
✅ 解读:
  • 遍历所有字段,检查有没有使用我们自定义的 @Inject 注解。

    复制代码
              try {
                  Class<?> type = field.getType();
                  Object instance = type.newInstance(); // 创建实例
✅ 解读:
  • field.getType():获取字段的类型,比如是 Service.class
  • type.newInstance():用 默认无参构造函数 实例化对象。

⚠️ 这里假设被注入的类必须有一个无参构造函数。

Java 复制代码
                    field.setAccessible(true);
                    field.set(target, instance);
✅ 解读:
  • setAccessible(true):允许访问私有字段。
  • field.set(target, instance):将我们创建好的实例注入到目标对象的字段中。

Java 复制代码
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException("Failed to inject " + field.getName());
                }
            }
        }
    }
}
✅ 解读:
  • 如果注入失败就打印异常并抛出运行时异常,方便调试。

💡 三、使用方式解析

Java 复制代码
public class MainActivity extends AppCompatActivity {

    @Inject
    Service service;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Injector.inject(this); // 调用注入器注入
        service.doSomething(); // 使用注入后的 service
    }
}
✅ 解读:
  • 使用了 @Inject 标记字段,告诉注入器需要注入这个字段。
  • Injector.inject(this):告诉系统对这个对象(MainActivity)做依赖注入。
  • service.doSomething():使用注入后的对象方法。

📌 总结核心原理

步骤 描述
1 定义注解,告诉系统哪些字段要注入
2 通过反射找出所有有注解的字段
3 为这些字段创建对应实例
4 把实例赋值给这些字段
相关推荐
2501_929157681 小时前
Switch 20.5.0系统最新PSP模拟器懒人包
android·游戏·ios·pdf
用户093 小时前
Kotlin Flow的6个必知高阶技巧
android·面试·kotlin
用户093 小时前
Flutter插件与包的本质差异
android·flutter·面试
用户093 小时前
Jetpack Compose静态与动态CompositionLocal深度解析
android·面试·kotlin
聆风吟º6 小时前
【Spring Boot 报错已解决】别让端口配置卡壳!Spring Boot “Binding to target failed” 报错解决思路
android·java·spring boot
非专业程序员Ping14 小时前
HarfBuzz概览
android·ios·swift·font
Jeled15 小时前
「高级 Android 架构师成长路线」的第 1 阶段 —— 强化体系与架构思维(Clean Architecture 实战)
android·kotlin·android studio·1024程序员节
明道源码16 小时前
Kotlin 控制流、函数、Lambda、高阶函数
android·开发语言·kotlin
消失的旧时光-194319 小时前
Kotlin × Gson:为什么遍历 JsonObject 要用 entrySet()
android·kotlin·数据处理·1024程序员节
G果20 小时前
安卓APP页面之间传参(Android studio 开发)
android·java·android studio