博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Arouter原理分析
阅读量:6445 次
发布时间:2019-06-23

本文共 14913 字,大约阅读时间需要 49 分钟。

在app的开发中,页面之间的相互跳转是最基本常用的功能。在Android中的跳转一般通过显式intent和隐式intent两种方式实现的,而Android的原生跳转方式会存在一些缺点:

显式intent的实现方式,因为会存在直接的类依赖的问题,导致耦合严重; 隐式intent的实现方式,则会出现规则集中式管理,导致协作变得困难; 可配置性较差,一般而言配置规则都是在Manifest中的,这就导致了扩展性较差; 跳转过程无法控制,一旦使用了StartActivity()就无法插手其中任何环节了,只能交给系统管理; 特别是当使用多组件化开发时,使用原生的路由方式很难实现完全解耦;

而阿里的ARouter路由框架具有解耦、简单易用、支持多模块项目、定制性较强、支持拦截逻辑等诸多优点,很好的解决了上述的问题。

Arouter原理

  1. ARouter在编译时会生成module下生成这些文件

    public class ARouter$$Root$$app implements IRouteRoot {   @Override   public void loadInto(Map
    > routes) { routes.put("app", ARouter$$Group$$app.class); } } public class ARouter$$Group$$app implements IRouteGroup { @Override public void loadInto(Map
    atlas) { atlas.put("/app/main", RouteMeta.build(RouteType.ACTIVITY, MainActivity.class, "/app/main", "app", null, -1, -2147483648)); atlas.put("/app/second", RouteMeta.build(RouteType.ACTIVITY, SecondActivity.class, "/app/second", "app", null, -1, -2147483648)); } } public class ARouter$$Providers$$app implements IProviderGroup { @Override public void loadInto(Map
    providers) { } }复制代码
  2. 接着看一下初始化方法

    public static void init(Application application) {     if (!hasInit) {         logger = _ARouter.logger;         _ARouter.logger.info(Consts.TAG, "ARouter init start.");         hasInit = _ARouter.init(application);         if (hasInit) {             _ARouter.afterInit();         }         _ARouter.logger.info(Consts.TAG, "ARouter init over.");     } }复制代码

    调用了_ARouter.init方法后接着就调用 _ARouter.afterInit方法

  3. 跟进_ARouter.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; }复制代码

    最主要的是ogisticsCenter.init(mContext, executor)这一句,其他的都是进行基本的赋值

    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {     mContext = context;     executor = tpe;     try {         long startInit = System.currentTimeMillis();         //先通过插件加载         loadRouterMap();         if (registerByPlugin) {             logger.info(TAG, "Load router map by arouter-auto-register plugin.");         } else { 			//加载routerMap             Set
    routerMap; if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) { logger.info(TAG, "Run with debug mode or new install, rebuild router map."); 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); } 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
    ())); } //开始加载 startInit = System.currentTimeMillis(); for (String className : routerMap) { if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) { // 加载ARouter$$RootXXX的IRouteRoot子类 ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex); } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) { // 加载ARouter$$InterceptorsXXX的IInterceptorGroup子类 ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex); } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) { // 加载ARouter$$ProvidersXXX的IProviderGroup子类 ((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() + "]"); } }复制代码

    从com.alibaba.android.arouter.routes这个包下面去扫描并加载到routerMap,本地进行缓存,如果是debug模式或者是新版本都需要从新进行扫描。然后对router进行分类并加载到Warehouse中进行管理。

  4. 然后跟进_ARouter.afterInit方法

    static void afterInit() {     interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation(); }复制代码

    afterInit方法是跟使用Arouter跳转activity的代码非常像,它返回了一个InterceptorService进行赋值。跟进去看一下,ARouter.getInstance()返回了一个Arouter的单例对象,然后接着调用了它的build方法

    public Postcard build(String path) {     return _ARouter.getInstance().build(path); }复制代码

    接着又获取了_ARouter的单例对象并调用其build方法。

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

    对path进行了判空,接着用另一种navigation方法获取了一个PathReplaceService,这个我们后面再看。再接着就是调用了extractGroup方法从path中获取到路由的group,然后再调用build(String path, String group)方法。

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

    跟上面的build方法比较类似,最后就返回了一个postcart对象。afterInit方法中最后就是拿着返回的postcart对象去调用navigation方法,navigation方法最终会调用到_ARouter的navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback)方法。

    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {     try {         LogisticsCenter.completion(postcard);     } catch (NoRouteFoundException ex) {         logger.warning(Consts.TAG, ex.getMessage());         if (debuggable()) {             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) {             callback.onLost(postcard);         } else {    // No callback for this invoke, then we use the global degrade service.             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()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.         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);                 }             }         });     } else {         return _navigation(context, postcard, requestCode, callback);     }     return null; }复制代码

    代码比较多,我们看主要的,首先是调用了LogisticsCenter.completion(postcard),这个方法是去加载路由信息,(前面LogisticsCenter只加载了相关group的一些东西,具体group中的路由还没有加载),如果已经加载就获取信息完成postcart对象其他字段的赋值。然后就是在拦截器中(如果是GreenChannel则直接调用)调用_navigation(context, postcard, requestCode, callback)方法。

    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
    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 { try { 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.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
    resultMap = TextUtils.splitQueryParameters(rawUri); Map
    paramsType = routeMeta.getParamsType(); if (MapUtils.isNotEmpty(paramsType)) { for (Map.Entry
    params : paramsType.entrySet()) { setValue(postcard, params.getValue(), params.getKey(), resultMap.get(params.getKey())); } postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{})); } postcard.withString(ARouter.RAW_URI, rawUri.toString()); } switch (routeMeta.getType()) { case PROVIDER: Class
    providerMeta = (Class
    ) 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; } } }复制代码

    if (null == groupMeta)这段代码中就是将这个path对应的group中的路由全部加载进来,然后又一次调用了completion(postcard)方法,下面就是对postcard进行赋值,switch语句中可以看到PROVIDER、FRAGMENT就是直接不通过拦截器的,而且PROVIDER的创建由框架控制,如果有实例就不重复创建了。让后就是真正的路由方法_navigation(context, postcard, requestCode, callback)

    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:             final Intent intent = new Intent(currentContext, postcard.getDestination());             intent.putExtras(postcard.getExtras());             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);             }             String action = postcard.getAction();             if (!TextUtils.isEmpty(action)) {                 intent.setAction(action);             }             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 {                 Object instance = fragmentMeta.getConstructor().newInstance();                 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());                 }                 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; }复制代码

    简单明了,ACTIVITY就直接跳转了返回null,PROVIDER就返回provider的实现类,BOARDCAST、CONTENT_PROVIDER、FRAGMENT也是通过反射创建对应的实例对象然后返回。

从整个Arouter的初始化流程,大家应该就明白了,Arouter其实就是将类的相关信息与我们给定的路由形成一个映射,这些映射关系在Arouter初始化的时候被加载进来,然后再通过我们定义好的路由来找到我们的类。所以我们在组件化中就可以通过路由来跳转其他module的activity。

转载地址:http://agpwo.baihongyu.com/

你可能感兴趣的文章
Testlink解决大用例导入问题
查看>>
Webstorm常用快捷键备忘
查看>>
nginx 的windows 基本配置
查看>>
js滚动加载到底部
查看>>
关于mac远程链接window服务器以及实现共享文件
查看>>
angular的service与factory
查看>>
Redis慢查询,redis-cli,redis-benchmark,info
查看>>
新建MVC3 编译出现 System.Web.Mvc.ModelClientValidationRule
查看>>
mysql主从同步从库同步报错
查看>>
Virtualbox 虚拟机网络不通
查看>>
poj 1017 Packets 贪心
查看>>
java概念基础笔记整理
查看>>
play music
查看>>
self parent $this关键字分析--PHP
查看>>
CC_UNUSED_PARAM 宏含义的解释
查看>>
leetcode124二叉树最大路径和
查看>>
设计模式——中介者模式
查看>>
VI常用命令和按键
查看>>
AngularJS笔记整理 内置指令与自定义指令
查看>>
学习OpenCV——BOW特征提取函数(特征点篇)
查看>>