美文网首页
ARouter系列二:@Autowired属性注入

ARouter系列二:@Autowired属性注入

作者: 一个追寻者的故事 | 来源:发表于2020-06-12 11:52 被阅读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了解的,看这些应该很容易。

    相关文章

      网友评论

          本文标题:ARouter系列二:@Autowired属性注入

          本文链接:https://www.haomeiwen.com/subject/hcartktx.html