ARoute源码分析之初始化过程

      已在多个项目中使用ARoute实现组件化间的路由通信,但是一直没有很完整的阅读过ARoute框架的源码。刚好这段时间想拜读一些知名框架的源码,那就从熟悉的ARoute开始吧!

若有错误的地方欢迎大家指正。


本篇博客就从ARoute的初始化流程开始,调用的初始化代码如下:

ARouter.init(getApplication());
ARouter.init(getApplication())方法实际调用的是_ARouter类里面的init(),ARoute中的代码如下:
    /**
     * Init, it must be call before used router.
     */
    public static void init(Application application) {
        if (!hasInit) {
            logger = _ARouter.logger;
            _ARouter.logger.info(Consts.TAG, "ARouter init start.");

            hasInit = _ARouter.init(application);

            、、、(暂时省略无关代码)
        }
    }

_ARoute中的init()代码如下:

    protected static synchronized boolean init(Application application) {
        mContext = application;
        LogisticsCenter.init(mContext, executor);
        logger.info(Consts.TAG, "ARouter init success!");
        hasInit = true;
        mHandler = new Handler(Looper.getMainLooper());

        return true;
    }

关键代码在于“LogisticsCenter.init(mContext, executor);”,下面就来分析这句代码里面都做了什么:

/**
 * LogisticsCenter init, load all metas in memory. Demand initialization
 */
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {

 ```
 try {
      ```
      Set<String> routerMap;
      // It will rebuild router map every times when debuggable.
      if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
          logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
          // These class was generated by arouter-compiler.
          routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
          if (!routerMap.isEmpty()) {
              context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE)
		       .edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
          }
          // Save new version name when router map update finishes.
          PackageUtils.updateVersion(context);    
      } else {
          logger.info(TAG, "Load router map from cache.");
          //Todo 遍历dex  根据包名获取所有的class文件,
          routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY,
	        Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
      }

      ```
      //todo  保存路由地址与类的对应关系
      for (String className : routerMap) {
        if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + 
            SUFFIX_ROOT)) {
            // This one of root elements, load root.
            ((IRouteRoot) (Class.forName(className).getConstructor().newInstance()))
		    .loadInto(Warehouse.groupsIndex);
        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + 
                    SEPARATOR + SUFFIX_INTERCEPTORS)) {
            // Load interceptorMeta
            ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance()))
		    .loadInto(Warehouse.interceptorsIndex);
        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + 
		            SEPARATOR + SUFFIX_PROVIDERS)) {
            // Load providerIndex    
            ((IProviderGroup) (Class.forName(className).getConstructor().newInstance()))
			.loadInto(Warehouse.providersIndex);
        }
      }
    }

     ```
 } catch (Exception e) {
     throw new HandlerException(TAG + "ARouter init logistics center exception!
                                [" + e.getMessage() + "]");
 }
}

上面代码隐藏了部分不重要的代码。

这段代码主要功能就是遍历dex文件,根据包名获取所有的类,然后判断类名中开头如果是:

“com.alibaba.android.arouter.routes.ARouter$$Root、 
com.alibaba.android.arouter.routes.ARouter$$Interceptors、  
com.alibaba.android.arouter.routes.ARouter$$Providers”

这三个类型,则构造出类并调用类中的loadInit()方法,那么接下来就看一下这三个类中的loadInit()具体做了什么:

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. 
 */
public class ARouter$$Group$$arouter implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/arouter/service/autowired", RouteMeta.build(RouteType.PROVIDER, 
              AutowiredServiceImpl.class, "/arouter/service/autowired", "arouter", null, 
              -1, -2147483648));
    atlas.put("/arouter/service/interceptor", RouteMeta.build(RouteType.PROVIDER,             
              InterceptorServiceImpl.class, "/arouter/service/interceptor", "arouter",     
              null, -1, -2147483648));
  }
}

三个类所在的位置如下图所示: 

        三个类都是相似的,接下来主要分析“ARouter$$Group/$/$arouter”。由其源码可知,这是ARoute自动生成的三个类,在loadInit()中的功能就是把各个URL对应的信息封装在RouteMeta对象中,然后存储到atlas,从上一步的源码可知这个传进来的atlas是Warehouse类中的静态Map类型变量,由此可知所有class与路由地址的映射关系都存储在这个Warehouse中。源码如下:

class Warehouse {
    // Cache route and metas
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    static Map<String, RouteMeta> routes = new HashMap<>();

    // Cache provider
    static Map<Class, IProvider> providers = new HashMap<>();

    static Map<String, RouteMeta> providersIndex = new HashMap<>();

    // Cache interceptor
    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new 
           UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
    static List<IInterceptor> interceptors = new ArrayList<>();

    static void clear() {
        routes.clear();
        groupsIndex.clear();
        providers.clear();
        providersIndex.clear();
        interceptors.clear();
        interceptorsIndex.clear();
    }
}

到此_ARouter.Init();就执行完了,再看回ARoute.init()方法中还做了什么:

 public static void init(Application application) {
        if (!hasInit) {
            ```
            hasInit = _ARouter.init(application);

            if (hasInit) {
                _ARouter.afterInit();
            }

            _ARouter.logger.info(Consts.TAG, "ARouter init over.");
        }
    }

从源码中可知,init完成后调用了_ARoute.afterInte()去创建了路由地址为“/arouter/service/interceptor”的拦截器,源码如下:

static void afterInit() {
    // Trigger interceptor init, use byName.
    interceptorService = (InterceptorService) 
       ARouter.getInstance().build("/arouter/service/interceptor").navigation();
    }

到此,ARoute的初始化流程源码分析暂时告一段落,下面贴上对应的时序图:

 分析完ARoute留下了两个疑问点:

1、ARoute是如何自动生成“ARouter/$/$Group$$xxx”这些文件的?

2、创建拦截器的代码其工作原理是什么:

(InterceptorService)ARouter.getInstance()
.build("/arouter/service/interceptor").navigation();

带着这两个问题,继续我们的ARoute源码阅读之旅......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值