ARouter系列二:@Autowired属性注入
如果对于 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
接口实现类是 AutowiredServiceImpl
,AutowiredServiceImpl
封装了对于所有 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了解的,看这些应该很容易。