ARouter系列二:@Autowired属性注入

2020-06-12  本文已影响0人  一个追寻者的故事

如果对于 ARouter 不是很了解的,建议先行阅读:
ARouter系列一:Activity跳转原理详解

一、Autowaired的 使用及辅助文件类生成

假设项目中有一个 Activity,名字叫:FirstActivity

package com.daddyno1.projectmoduledemo;
...
public class FirstActivity extends AppCompatActivity {
    
    @Autowired int age;
    @Autowired(name = "name") String mName;
    @Autowired Phone phone;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        // 使用ARouter 对本页面的属性通过传入的参数进行注入。
        ARouter.getInstance().inject(this);
    }
}

定义了三个属性 age、mName 和 phone,分别用 @Autowired注解,其中Phone是自定义类型,实现了 Serializable接口。

package com.daddyno1.projectmoduledemo.bean;
...
public class Phone implements Serializable {
    public Phone(String type){
        this.type = type;
    }
    public String type;
}

项目编译,我们看一下,ARouter通过 APT帮助我们生成的辅助类。
com.daddyno1.projectmoduledemo 包下生成了 FirstActivity$$ARouter$$Autowired 源文件:

package com.daddyno1.projectmoduledemo;
...
/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class FirstActivity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    FirstActivity substitute = (FirstActivity)target;
    substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
    substitute.mName = substitute.getIntent().getStringExtra("name");
    substitute.phone = (com.daddyno1.projectmoduledemo.bean.Phone) substitute.getIntent().getSerializableExtra("phone");
  }
}

辅助文件的逻辑很简单,通过 Intent 拿到页面 FirstActivity 传递过来的参数,然后再赋值给 FirstActivity 的属性。接下来应该很明朗了,就是如何使用这个辅助类呢,通过 反射创建 FirstActivity$$ARouter$$Autowired 对象,然后调用其 inject 方法,传入的参数就是 FirstActvitiy对象,这样 FirstActivity 的属性就会自动注入值。

因为是通过反射创建的辅助类,所以为了提高效率,通过反射创建的FirstActivity$$ARouter$$Autowired 对象,会被缓存下来,下次再打开同一个页面,其辅助类的实例就会直接从缓存读取辅助对象,提高效率。

注意,生成的辅助类名字,都会以 $$ARouter$$Autowired作为后缀。同时实现 ISyringe接口:

//抽象了一个注入的方法
public interface ISyringe {
    void inject(Object target);
}
二、ARouter 的注入逻辑源码分析

我们在 FirstActiviy 中使用 ARouter.getInstance().inject(this); 就会实现属性自动注入。接下来分析一下如何实现的。之后会调用 _ARouter#inject

final class _ARouter{
    static void inject(Object thiz) {
        //获取 AutowiredService 的接口实现,拿到最终进行注入的服务实现
        AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
        if (null != autowiredService) {
            //实现注入
            autowiredService.autowire(thiz);
        }
    }
}

通过 /arouter/service/autowired 最终拿到的 AutowiredService 接口实现类是 AutowiredServiceImplAutowiredServiceImpl 封装了对于所有 Activity 进行属性注入的逻辑处理。

package com.alibaba.android.arouter.core;
...
@Route(path = "/arouter/service/autowired")
public class AutowiredServiceImpl implements AutowiredService {
    /**这是一个缓存,key:被注入的Activity全类名,value:此Activity辅助类实例。因为辅助类的实例
        通过反射获取,消耗性能,这样缓存起来,下次再进入页面的时候就会快。
    **/
    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) {
        // 所要注入的Activity的全类名: com.daddyno1.projectmoduledemo.FirstActivity
        String className = instance.getClass().getName();
        try {
            // 如果 所要注入的类的全类名在黑名单中,则不进行属性自动注入。
            if (!blackList.contains(className)) {
                //从缓存中获取辅助类对象
                ISyringe autowiredHelper = classCache.get(className);
                if (null == autowiredHelper) {  // No cache.
                    //如果没缓存,则反射构建辅助类对象。如:com.daddyno1.projectmoduledemo.FirstActivity$$ARouter$$Autowired
                    autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
                }
                // 调用注入。如:FirstActivity$$ARouter$$Autowired.inject
                autowiredHelper.inject(instance);
                //放入缓存
                classCache.put(className, autowiredHelper);
            }
        } catch (Exception ex) {
            /** 此 Activity 加入黑名单。下次就不会再进行处理。比如:Activity中没有使用 @Autowired 注解,
          结果却使用了 ARouter.getInstance().inject(this); 这样一来,在加载生成的辅助类的时候发现失败,
          以后就会进入到黑名单,不会再理会inject这个行为了。
            **/
            blackList.add(className);    // This instance need not autowired.
        }
    }
}

至此,一次完整的 Activity 属性被自动注入的过程分析完成。如果之前对ButterKnife了解的,看这些应该很容易。

上一篇下一篇

猜你喜欢

热点阅读