Arouter 原理记录

Arouter解决了什么问题?怎么解决的?

带着这两个问题简单看了一下Arouter的源码。

先说第一个问题,Arouter解决了什么问题?

:组件化中由于依赖关系导致Activity等组件不能直接显式调用问题。

如下图:

这是一个简单的组件化的模型,假设3个model分别有三个Activity:

app——Activity_a

modelA——Activity_b

modelB——Activity_c

正常情况下要实现三个activity之间的跳转可以这样写:

//1.app
startActivity(new Intent(this,Activity_b.class));
//2.modelA
startActivity(new Intent(this,Activity_c.class));
//3.modelB
startActivity(new Intent(this,Activity_a.class));

但实际上由于依赖关系,只有1能实现,而其它两个都会有编译错误。

解决的方式就是共同依赖一个model:router。在router里创建一个容器类,例如:

public class BaseHouse {
    public static Map<String,Class<?>> activityHouse=new HashMap<>();

    public static void put(String router,Class cl){
        activityHouse.put(router,cl);
    }

    public static Class get(String router){
        return activityHouse.get(router);
    }
}

在app初始化时,将所有的activity保存

   static {
        BaseHouse.put("a",Activity_a.class);
        BaseHouse.put("b", Activity_b.class);
        BaseHouse.put("c", Activity_c.class);
    }

而使用时通过索引进行请求:

//1.app
startActivity(new Intent(this,Activity_b.class));
//2.modelA
startActivity(new Intent(this,BaseHouse.get("c"));
//3.modelB
startActivity(new Intent(this,BaseHouse.get("a"));

这样既能使用显示意图,又能解决依赖导致的编译问题,这是我理解的Arouter的基本原理和作用。而关于网上大幅介绍的注解,其实只是锦上添花的操作,是Arouter优秀设计的体现,和原理关系不大。

 

下面简单看一下Arouter是怎么初始化我们上面提到的索引对应的:

使用前需要先调用ARouter.init()方法进行初始化,跟进该方法:

最终到LogisticsCenter#init方法

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

        try {
            long startInit = System.currentTimeMillis();
            //billy.qi modified at 2017-12-06
            //load by plugin first
            loadRouterMap();
            if (registerByPlugin) {
                logger.info(TAG, "Load router map by arouter-auto-register plugin.");
            } else {
                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.
                    // 1.此处从dex中获取到所有通过注解生成的类
                    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 {
                    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();
                //2.执行对应方法,将索引和类添加到map缓存
                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() + "]");
        }
    }

这里比较主要的就是上面两处中文注释的地方,通过上面这一步,索引关系就建立了,最终保存在

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();
    }
}

这一步就和上面示例中的BaseHouse的作用对应上了,当然这里相比示例进行了一些包装,使Arouter的功能更加丰富,但是原理不变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值