ARouter源码解析

作者: MingMing很忙 | 来源:发表于2020-05-25 20:05 被阅读0次

    1-初始化

    ARouter.init()开始,init方法的主要工作就是ARouter实例化,_ARouter的初始化。_ARouter是具体实现类。这里用到了外观模式,将所有API通过ARouter暴露,具体实现则交由_ARouter

    //ARouter.java
    public static void init(Application application) {
            if (!hasInit) {
                //日志类
                logger = _ARouter.logger;
                _ARouter.logger.info(Consts.TAG, "ARouter init start.");
                //@1._ARouter初始化
                hasInit = _ARouter.init(application);
    
                if (hasInit) {
                    //@4.通过路由开启Service,预解析拦截器
                    _ARouter.afterInit();
                }
    
                _ARouter.logger.info(Consts.TAG, "ARouter init over.");
            }
        }
    

    @1._ARouter的初始化:

    protected static synchronized boolean init(Application application) {
            mContext = application;
            //@2.LogisticsCenter初始化
            LogisticsCenter.init(mContext, executor);
            logger.info(Consts.TAG, "ARouter init success!");
            hasInit = true;
            //主线程Looper创建一个Handler
            mHandler = new Handler(Looper.getMainLooper());
    
            return true;
        }
    

    @2.LogisticsCenter初始化。主要工作就是初始化所有类的map。在编译期通过gradle插件(arouter-compiler)扫描文件,生成路由映射文件,apt生成路由映射关系文件。

    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
            mContext = context;
            executor = tpe;
    
            try {
                。。。
                if (registerByPlugin) {
                    。。。
                } else {
                    Set<String> routerMap;
                    //debuggable模式或版本更新,重新获取routerMap映射表
                    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.
                        //遍历arouter-compiler生成的包名下所有文件,读取routerMap路由映射表,将routerMap存储在sp中
                        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();
                        }
    
                        PackageUtils.updateVersion(context);    // Save new version name when router map update finishes.
                    } else {
                        //直接从sp中读取routerMap。set<String>类型,存储的是className
                        logger.info(TAG, "Load router map from cache.");
                        routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
                    }
    
                    logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
                    startInit = System.currentTimeMillis();
                    //@3.遍历routerMap,根据文件类型存储到Warehouse对应的字段。通过反射实例化对象,调用loadInto实现。
                    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);
                        }
                    }
                }
    
                logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");
    
                if (Warehouse.groupsIndex.size() == 0) {
                    logger.error(TAG, "No mapping files were found, check your configuration please!");
                }
    
                if (ARouter.debuggable()) {
                    logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));
                }
            } catch (Exception e) {
                throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
            }
        }
    

    @3.这里存储到Warehose里的主要是三个HashMap,分别是groupsIndex、interceptorsIndex、providersIndex

    • interceptorsIndex-TreeMap实现,根据拦截器的优先级自平衡的有序结构,红黑树实现。key是优先级,value是拦截器类名
    • groupsIndex-key是路由的group,value是该group下的路由映射关系类
    • providersIndex-

    存储过程是通过routerMap拿到className,反射生成实例调用其loadInto方法,该方法是APT在@Route注解的类中自动生成的代码

    public class ARouter$$Root$$app implements IRouteRoot {
      @Override
      public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
        //key为分组名,即路径的第一段,value为分组中所有的映射关系
        routes.put("service", ARouter$$Group$$service.class);
        routes.put("test", ARouter$$Group$$test.class);
      }
    }
    
    //将module中使用@Route注解的activity或Fragment添加到集合中,这里的方法会在之后调用
    public class ARouter$$Group$$test implements IRouteGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> atlas) {
        atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test", new java.util.HashMap<String, Integer>(){{put("pac", 9); put("ch", 5); put("fl", 6); put("obj", 10); put("name", 8); put("dou", 7); put("boy", 0); put("objList", 10); put("map", 10); put("age", 3); put("url", 8); put("height", 3); }}, -1, -2147483648));
        atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test", new java.util.HashMap<String, Integer>(){{put("key1", 8); }}, -1, -2147483648));
        atlas.put("/test/activity3", RouteMeta.build(RouteType.ACTIVITY, Test3Activity.class, "/test/activity3", "test", new java.util.HashMap<String, Integer>(){{put("name", 8); put("boy", 0); put("age", 3); }}, -1, -2147483648));
        atlas.put("/test/activity4", RouteMeta.build(RouteType.ACTIVITY, Test4Activity.class, "/test/activity4", "test", null, -1, -2147483648));
        atlas.put("/test/fragment", RouteMeta.build(RouteType.FRAGMENT, BlankFragment.class, "/test/fragment", "test", null, -1, -2147483648));
        atlas.put("/test/webview", RouteMeta.build(RouteType.ACTIVITY, TestWebview.class, "/test/webview", "test", null, -1, -2147483648));
      }
    }
    

    @4._ARouter.afterInit()方法。通过ARouter获取管理拦截器的Service的实例,并开启服务进行拦截器的一些初始化工作。

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

    InterceptorServiceImpl服务主要是实例化拦截器,并将实例添加到Warehose的interceptors中

    @Route(path = "/arouter/service/interceptor")
    public class InterceptorServiceImpl implements InterceptorService {
        private static boolean interceptorHasInit;
        private static final Object interceptorInitLock = new Object();
    
        @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();
                    try {
                        IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
                        iInterceptor.init(context);
                        Warehouse.interceptors.add(iInterceptor);
                    } catch (Exception ex) {
                        throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");
                    }
                }
            ...
        }
    }
    

    总结初始化过程:

    • (1)ARouter.init()-->_ARouter.init()-->LogisticsCenter.init()
    • (2)debuggable()模式或新版本,则从指定的router-compiler生成的目录遍历文件加载路由映射表routerMap,并缓存到SP;否则直接读取SP中的routerMap
    • (3)遍历routerMap,根据className的类型依次初始化并存储到内存中。Warehose对应的三个map。groupsIndex(gourp名-该分组下的所有映射关系类名)、interceptorsIndex(优先级-拦截器名)、providersIndex()
    • (4)_ARouter.afterInit().通过路由打开InterceptorService,遍历Warehose中的interceptorsIndex,实例化对象并存储到Warehose.interceptors


      图1-初始化流程

    2-路由跳转

    跳转的代码从ARouter.getInstance()-->ARouter.build()

    ARouter.getInstance().build("/test/activity").navigation();
    

    ARouter.build()-->_ARouter.getInstance().build()

    protected Postcard build(String path) {
            if (TextUtils.isEmpty(path)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
                //PathReplaceService是实现路径动态变化,也就是重定向功能。
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    //拿到通过PathReplaceService修改后的path
                    path = pService.forString(path);
                }
                //@1.extractGroup(path)解析出group名
                return build(path, extractGroup(path));
            }
        }
    

    @1._ARouter.build方法。返回一个Postcard对象用于存储跳转信息。Postcard继承RouteMeta,封装了路由类型、@Autowired属性集合Map(属性名-属性类型)等信息

    protected Postcard build(String path, String group) {
            if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    path = pService.forString(path);
                }
                return new Postcard(path, group);
            }
        }
    

    然后调用_ARouter.navigation方法

    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            。。。
            try {
                //@2.查找对应的路由信息
                LogisticsCenter.completion(postcard);
            } catch (NoRouteFoundException ex) {
                logger.warning(Consts.TAG, ex.getMessage());
    
                if (debuggable()) {
                    // Show friendly tips for user.
                    runInMainThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(mContext, "There's no route matched!\n" +
                                    " Path = [" + postcard.getPath() + "]\n" +
                                    " Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
                        }
                    });
                }
    
                if (null != callback) {
                    //调用onLost回调
                    callback.onLost(postcard);
                } else {
                    // 或者调用DegradeService全局降级的onLost处理
                    DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
                    if (null != degradeService) {
                        degradeService.onLost(context, postcard);
                    }
                }
    
                return null;
            }
    
            if (null != callback) {
                callback.onFound(postcard);
            }
    
            if (!postcard.isGreenChannel()) {   // 需要拦截处理
                //@3.调用InterceptorService拦截
                interceptorService.doInterceptions(postcard, new InterceptorCallback() {
                
                    @Override
                    public void onContinue(Postcard postcard) {
                        _navigation(context, postcard, requestCode, callback);
                    }
    
                    
                    @Override
                    public void onInterrupt(Throwable exception) {
                        if (null != callback) {
                            callback.onInterrupt(postcard);
                        }
    
                        logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
                    }
                });
            } else {//不需要拦截处理
                //@3.最终跳转
                return _navigation(context, postcard, requestCode, callback);
            }
    
            return null;
        }
    

    @2.LogisticsCenter.completion方法。主要工作就是从Warehouse中懒加载路由信息并缓存到Postcard,包括@Autowired注解的参数列表封装到Postecard的mBundle中

    public synchronized static void completion(Postcard postcard) {
            if (null == postcard) {
                throw new NoRouteFoundException(TAG + "No postcard!");
            }
    
            RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
            if (null == routeMeta) {    // Maybe its does't exist, or didn't load.
                Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // Load route meta.
                if (null == groupMeta) {
                    throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
                } else {
                    // Load route and cache it into memory, then delete from metas.
                    try {
                        if (ARouter.debuggable()) {
                            logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                        }
                        //从Warehouse.groupIndex读取到对应的映射列表。并将列表中的路由加到Warehouse.routes
                        //同时已加载的group从groupIndex中移除
                        IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                        iGroupInstance.loadInto(Warehouse.routes);
                        Warehouse.groupsIndex.remove(postcard.getGroup());
    
                        if (ARouter.debuggable()) {
                            logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                        }
                    } catch (Exception e) {
                        throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
                    }
                    //再次加载
                    completion(postcard);   // Reload
                }
            } else {
                //将路由参数存储到Postcard
                postcard.setDestination(routeMeta.getDestination());
                postcard.setType(routeMeta.getType());
                postcard.setPriority(routeMeta.getPriority());
                postcard.setExtra(routeMeta.getExtra());
    
                Uri rawUri = postcard.getUri();
                if (null != rawUri) {   // Try to set params into bundle.
                    Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
                    Map<String, Integer> paramsType = routeMeta.getParamsType();
    
                    if (MapUtils.isNotEmpty(paramsType)) {
                        // Set value by its type, just for params which annotation by @Param
                        for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
                            setValue(postcard,
                                    params.getValue(),
                                    params.getKey(),
                                    resultMap.get(params.getKey()));
                        }
    
                        // Save params name which need auto inject.
                        postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
                    }
    
                    // Save raw uri
                    postcard.withString(ARouter.RAW_URI, rawUri.toString());
                }
    
                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);
                        if (null == instance) { // There's no instance of this provider
                            IProvider provider;
                            try {
                                provider = providerMeta.getConstructor().newInstance();
                                provider.init(mContext);
                                Warehouse.providers.put(providerMeta, provider);
                                instance = provider;
                            } catch (Exception e) {
                                throw new HandlerException("Init provider failed! " + e.getMessage());
                            }
                        }
                        postcard.setProvider(instance);
                        postcard.greenChannel();    // Provider should skip all of interceptors
                        break;
                    case FRAGMENT:
                        postcard.greenChannel();    // Fragment needn't interceptors
                    default:
                        break;
                }
            }
        }
    

    @3.跳转_navigation

    • Activity。则构建Intent,将相关信息封装到Intent,包括action、bundle等。在主线程调用startActivity跳转。
    • Fragment。创建Fragment实例,设置bundle参数,返回该Fragment实例
    private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            final Context currentContext = null == context ? mContext : context;
    
            switch (postcard.getType()) {
                case ACTIVITY:
                    // 构建intent
                    final Intent intent = new Intent(currentContext, postcard.getDestination());
                    intent.putExtras(postcard.getExtras());
    
                    // 设置Activity启动模式
                    int flags = postcard.getFlags();
                    if (-1 != flags) {
                        intent.setFlags(flags);
                    } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    }
    
                    // 设置Actions
                    String action = postcard.getAction();
                    if (!TextUtils.isEmpty(action)) {
                        intent.setAction(action);
                    }
    
                    // 主线程调用startActivity跳转
                    runInMainThread(new Runnable() {
                        @Override
                        public void run() {
                            startActivity(requestCode, currentContext, intent, postcard, callback);
                        }
                    });
    
                    break;
                case PROVIDER:
                    return postcard.getProvider();
                case BOARDCAST:
                case CONTENT_PROVIDER:
                case FRAGMENT:
                    Class fragmentMeta = postcard.getDestination();
                    try {
                        //生成fragment实例
                        Object instance = fragmentMeta.getConstructor().newInstance();
                        //设置bundle参数
                        if (instance instanceof Fragment) {
                            ((Fragment) instance).setArguments(postcard.getExtras());
                        } else if (instance instanceof android.support.v4.app.Fragment) {
                            ((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
                        }
                        //返回fragment实例
                        return instance;
                    } catch (Exception ex) {
                        logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
                    }
                case METHOD:
                case SERVICE:
                default:
                    return null;
            }
    
            return null;
        }
    

    跳转过程总结:封装Postcard -> 查找信息集合,实例化目标类 -> 返回实例或者跳转。

    • (1)ARouter.getInstance().build()-->_ARouter.getInstance().build()
    • (2)PathReplaceService执行path重定向
    • (3)_ARouter.navigation-->LogisticsCenter.completion。
    • (4)Warehouse的routes中取路由参数,获取失败则解析groupsIndex中对应group的路由列表,添加到routes中。
    • (5)添加完毕再次从routes获取,将路由参数封装到Poster并返回
    • (6)启动InterceptorService执行拦截器
    • (7)执行_navigation。若是Activity,则将poster信息封装到Intent,通过在主线程startActivity跳转。若是Fragment,根据poster信息创建Fragment实例并返回


      图2-跳转流程

    3-@Interceptor拦截

    @4.InterceptorService的doInterceptions进行拦截处理。通过CountDownLatch实现计数阻塞。计数初始值为拦截器个数,每执行一个拦截器操作计数-1。计数为0或timeout则取消线程阻塞

    @Override
    public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
        if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
            ... //省略同步等待初始化
            LogisticsCenter.executor.execute(new Runnable() {
                @Override
                public void run() {
                    //拦截器个数作为计数初始值
                    CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
                    try {
                        _excute(0, interceptorCounter, postcard);
                        //阻塞线程直到超时,或者计数归0
                        interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
                        if (interceptorCounter.getCount() > 0) { //拦截超时
                            callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
                        } else if (null != postcard.getTag()) {  // 被拦截
                            callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
                        } else { //放行
                            callback.onContinue(postcard);
                        }
                    } catch (Exception e) {
                        callback.onInterrupt(e);
                    }
                }
            });
        } else {
            callback.onContinue(postcard);
        }
    }
    
    /**
     * Excute interceptor
     *
     * @param index    current interceptor index
     * @param counter  interceptor counter
     * @param postcard routeMeta
     */
    private static void _excute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
        //有下一个拦截器
        if (index < Warehouse.interceptors.size()) {
            IInterceptor iInterceptor = Warehouse.interceptors.get(index);
            iInterceptor.process(postcard, new InterceptorCallback() {
                @Override
                public void onContinue(Postcard postcard) {
                    // 如果放行,则计数减1,执行后一个拦截器
                    counter.countDown();
                    _excute(index + 1, counter, postcard); 
                }
    
                @Override
                public void onInterrupt(Throwable exception) {
                    // 拦截,将exception存入postcard的tag字段,计数归零
                    postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());
                    counter.cancel();
                });
            }
        }
    

    4-@Autowired参数注解

    @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) {
            String className = instance.getClass().getName();
            try {
                if (!blackList.contains(className)) {
                    ISyringe autowiredHelper = classCache.get(className);
                    if (null == autowiredHelper) {  // No cache.
                        autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
                    }
                    //从mBundle中取出参数赋值
                    autowiredHelper.inject(instance);
                    classCache.put(className, autowiredHelper);
                }
            } catch (Exception ex) {
                blackList.add(className);    // This instance need not autowired.
            }
        }
    }
    

    ISyringe是apt在注解@Autowired时自动生成一个对应的ISyringe实现。将bundle中的数据取出,赋值给@Autowired注解的属性。

    总的参数注入过程:

    • ARouter.inject-->_ARouter.inject
    • AutowiredServiceImpl.autowire
    • 生成apt自动生成的ISyringe类的实例
    • ISyringe。inject将Poster中的mBundle参数赋值给具体的属性
      先通过开启AutowiredService来实现

    相关文章

      网友评论

        本文标题:ARouter源码解析

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