美文网首页Android技术知识Android知识Android开发经验谈
ARouter源码分析(3)-跨模块加载实现类与参数的自动注入

ARouter源码分析(3)-跨模块加载实现类与参数的自动注入

作者: susion哒哒 | 来源:发表于2018-10-20 18:17 被阅读11次

文章来源自作者的Android进阶计划(https://github.com/SusionSuc/AdvancedAndroid)

其实在第一篇文章的时候已经介绍过ARouter中的InterceptorServiceGlobalDegradeService也是框架在运行时期动态加载的。即使这两个类位于其它的模块。
所以ARouter也是具有WMRouterServiceLoader相似的功能的。本文就来看一下这个功能。

拦截器Service的加载

先来看一下ARouter的拦截器的实现类:

@Route(path = "/arouter/service/interceptor")
public class InterceptorServiceImpl implements InterceptorService {}

即也使用了@Route注解标记,按照我们前面文章的分析,这个类也会在运行的时候被动态的加载到路由表Warehouse.routesWarehouse.groupIndex中。

我们看一下ARouter是如何在代码中获取这个类的实现类的:

static void afterInit() { //这个代码在ARouter初始化完毕后调用
    interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}

这里可能就有疑问了,为什么ARouter.getInstance().build("/arouter/service/interceptor").navigation()可以得到一个对象?

我们已经知道@Route标记的类在RouteProcessor处理时会生成对应的RouteMeta。其实RouterMeta是有类型的,我们来看一下注解扫描生成RouteMeta那一段代码:

    TypeMirror tm = element.asType(); //tm 即注解标注的那个类
    if (types.isSubtype(tm, type_Activity)) {// Activity
        routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
        routeMeta.setInjectConfig(injectConfig);
    } else if (types.isSubtype(tm, iProvider)) {// IProvider
        routeMeta = new RouteMeta(route, element, RouteType.PROVIDER, null);
    } else if (types.isSubtype(tm, type_Service)) { // Service
        routeMeta = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
    }

即如果被注解标注的类是个Activity,那么RouteMeta的类型就是RouteType.ACTIVITY。如果是IProvider,那么对应的类型就是RouteType.PROVIDER

其实InterceptorServiceImpl就是IProvider类型:

public interface InterceptorService extends IProvider {
    interceptions(Postcard postcard, InterceptorCallback callback);
}

我们前面只看了ARouter只在路由过程中对RouteType.ACTIVITY的处理,这里我们看一下对RouteType.PROVIDER的处理:

    //_ARouter.java
   private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        switch (postcard.getType()) {
            case ACTIVITY:
                //对activity进行跳转
                break;
            case PROVIDER:
                return postcard.getProvider();
            ....
            default:
                return null;
        }
        return null;
    }

即对于RouteType.PROVIDER直接返回了postcard.getProvider()。 好我们来看一下postcard.getProvider()是什么? 我们来看一下LogisticsCenter根据RouteMeta组装Postcard的那一段代码:

    switch (routeMeta.getType()) {
        case PROVIDER:  // if the route is provider, should find its instance
            // Its provider, so it must implement IProvider
            Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
            IProvider instance = Warehouse.providers.get(providerMeta);
            //..如果 instance 为空的话则实例化 `providerMeta`对应的类,然后放入到`Warehouse.providers`
            postcard.setProvider(instance);
            postcard.greenChannel();    // Provider should skip all of interceptors
            break;
        case FRAGMENT:
            postcard.greenChannel();    // Fragment needn't interceptors
        default:
            break;
    }

其实这里就可以猜测,对于@Route标记的IProvider接口,也会创建一个Warehouse.providers,用来保存这些实例。

所以postcard.getProvider()就是一个 InterceptorServiceImpl对象。综上:

static void afterInit() { //这个代码在ARouter初始化完毕后调用
    interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}

interceptorService就是InterceptorServiceImpl对象。

好到这里我们知道了InterceptorService是如何加载的了。Interceptor是怎加载的呢?

这里就不去仔细追究源码了,直接解释一下大致原理。

  1. 在ARoute中,拦截器可以使用@Interceptor来标注
  2. InterceptorProcessor会动态生成一个注册文件,类似于Activity的路由节点注册的java类。
  3. 在ARouter初始化的时候,会注册到Warehouse.interceptors
  4. InterceptorService在初始化的时候,会实例化Warehouse.interceptors表中记录的类

我们只看一下InterceptorServiceImpl的初始化方法,来证明上面所说的 :

    @Override public void init(final Context context) {
         if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {  //这段代码是在异步线程执行的
            for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
                Class<? extends IInterceptor> interceptorClass = entry.getValue();
                IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
                iInterceptor.init(context);
                Warehouse.interceptors.add(iInterceptor);
            }
            ......
        }
    }

IProvider 的妙用

看了上面这个功能,我们是不是可以利用它来加载一个其他库的实现类,比如一个UI的实现类? 答案是可以的,比如我们在一个库中定义了这个类:

@Route(path = "/custom/ui1")
public class MyCustomUi implements IProvider {  //必须实现 IProvider 接口
    public MyCustomUi() { }//要提供默认构造方法
    @Override
    public void init(Context context) {}
}

我们在主工程中,这样就可以获得它的实例:

IProvider ui1 = (IProvider) ARouter.getInstance().build("/custom/ui1").navigation();

这个功能是不是和WMRouterServiceLoader有异曲同工之妙?

@Autowired 参数的自动注入

ARouter是支持在Activity的属性上标记@Autowired注解,然后在跳转的时候自动将参数赋值到这些属性上。比如:

ARouter.getInstance()
                .build("/test/activity1")
                .withInt("age", 23)
                .navigation();

@Route(path = "/test/activity1")
public class Test1Activity extends AppCompatActivity {

    @Autowired
    int age = 10; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ARouter.getInstance().inject(this);  // 在 onCreate中必须调用这个方法
    }
}

其实这个功能的实现也是基于上面@Route机制的,因此这里就大致讲一下原来和关键代码:

  1. AutowiredProcessor会在编译时扫描@Autowired注解,并生成下面的文件
public class Test1Activity$$ARouter$$Autowired implements ISyringe {
  @Override
  public void inject(Object target) {
    Test1Activity substitute = (Test1Activity)target;
    substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
  }
}
  1. ARouter.getInstance().inject(this); 最终会调用下面代码
static void inject(Object thiz) {
    AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
    if (null != autowiredService) {
        autowiredService.autowire(thiz);
    }
}
  1. 来看一下AutowiredService的实现类
@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) {  //instance 就是  Test1Activity的实例
        ....
        //autowiredHelper其实就是Test1Activity$$ARouter$$Autowired
        autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();  
        autowiredHelper.inject(instance); // 调用 Test1Activity$$ARouter$$Autowired.inject()
        ...
    }
}

相关文章

网友评论

    本文标题:ARouter源码分析(3)-跨模块加载实现类与参数的自动注入

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