ARouter 之注解 @JvmField 和 @Autowired

博客介绍了 ARouter 中 @Autowired 注解用于简化 Activity 和 Fragment 数据传递参数注入的方法,包括注解属性定义。还说明了其使用方式、源码调用链,以及在 Kotlin 中 @Autowired 需搭配 @JvmFiled 使用的原因,避免因反射无法访问私有变量导致赋值失败。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 定义

  • 在 Activity 进行数据传递一般都会通过 getIntent().putxxx()/getxxx() 方法;在 Fragment 中进行数据传递一般都会通过 getArguments().getxxx() 方法,如果传递的字段过多,可能会写很多个取值语句。为了简化这些繁琐的步骤,ARouter 提供了使用注解的方式来完成参数的注入,这是通过 @Autowired 来实现的。
/**
 * Annotation for field, which need autowired.
 *
 * @author zhilong <a href="mailto:zhilong.lzl@alibaba-inc.com">Contact me.</a>
 * @version 1.0
 * @since 2017/2/20 下午4:26
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Autowired {

    // Mark param's name or service name.
    String name() default "";

    // If required, app will be crash when value is null.
    // Primitive type wont be check!
    boolean required() default false;

    // Description of the field
    String desc() default "";
}
  • name():定义了属性获取值的 key
  • required():定义了当前属性是否是必须的,默认为 false。如果是必须的,但是值为 null,APP 会 crash。基本类型不会做 null 校验。
  • desc():字段说明

2. 使用

  • 若属性名保持一致,name 可不加
@Autowired(name = "isForFreeVip")
var isForFreeVip = false
  • 对应生成的注解文件:
/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class KGLoginActivity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    KGLoginActivity substitute = (KGLoginActivity)target;
    // isForFreeVip 不加 @JvmFiled 注解的话,是 private 遍历,无法通过下面的方式访问到,必须通过 setForFreeVip() 去赋值,那在此处就会赋值失败
    substitute.isForFreeVip = substitute.getIntent().getBooleanExtra("isForFreeVip", substitute.isForFreeVip);
  }
}
  • 赋值操作在 inject() 方法中,这个方法的调用链如下:ARouter.inject() -> _ARouter.inject() -> AutowiredServiceImpl.autowire() -> ISyringe.inject(Object)

3. 源码分析

  • 之前说过的调用链是:ARouter.inject() -> _ARouter.inject() -> AutowiredServiceImpl.autowire() -> ISyringe.inject()

  • ARouter.inject()

public void inject(Object thiz) {
    _ARouter.inject(thiz);
}
  • _ARouter.inject()
static void inject(Object thiz) {
    // 去路由表里查找 "/arouter/service/autowired" 的实现类,就是 AutowiredServiceImpl
    AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
    if (null != autowiredService) {
        autowiredService.autowire(thiz);
    }
}
  • AutowiredServiceImpl.autowire()
@Route(path = "/arouter/service/autowired")
public class AutowiredServiceImpl implements AutowiredService {
    // 存储反射实例
    private LruCache<String, ISyringe> classCache;
    // 存放不需要注入操作的类
    private List<String> blackList;

    @Override
    public void init(Context context) {
        classCache = new LruCache<>(66);
        blackList = new ArrayList<>();
    }
    
    @Override
    public void autowire(Object instance) {
        String className = instance.getClass().getName();
        try {
            // 不在黑名单
            if (!blackList.contains(className)) {
                // 从缓存里取出对应的实例对象
                ISyringe autowiredHelper = classCache.get(className);
                if (null == autowiredHelper) {  // No cache.
                    // 如果没有缓存,通过反射的方式,创建实例对象
                    autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
                }
               
                // 就是编译期生成的 XXX$$ARouter$$Autowired 文件中的 inject 方法
                autowiredHelper.inject(instance);
                // 将实例对象缓存起来
                classCache.put(className, autowiredHelper);
            }
        } catch (Exception ex) {
            // 如果发生异常,加入黑名单
            blackList.add(className);    // This instance need not autowired.
        }
    }
}

4. 为什么 @Autowired 要搭配 @JvmFiled 同时使用?

  • ARouter 对 kotlin 中的 @Autowired 注解赋值,为什么需要对变量用 @JvmFiled 标记?

  • @JvmFiled 的作用:不加 @JvmFiled 默认就会生成 setter() 和 getter() 方法,赋/取值操作实际上是调用 setter() 和 getter(),而变量本身对 java 代码是不可见的,可以认为是 private。使用 @JvmField 标记后,反编译后的 java 代码中发现,不会再自动生成对应的 setter() 和 getter() 方法,此时变量对 java 代码也是可见的。

  • 查看源码 com.alibaba.android.arouter.core.AutowiredServiceImpl#autowire() 方法中,通过反射获取变量名并进行赋值,但是反射时并没有设置 setAccessible(true)【这句话的作用是允许访问私有变量】,不能访问私有变量,从而导致赋值失败

  • 去掉 @JvmFiled 反编译后的结果:

@Autowired
private boolean isForFreeVip;

public final boolean isForFreeVip() {
  return this.isForFreeVip;
}

public final void setForFreeVip(boolean var1) {
  this.isForFreeVip = var1;
}
  • 加上 @JvmFiled 反编译后的结果:
@JvmField
@Autowired
public boolean isForFreeVip;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值