ARouter初始化及跳转原理

2023-11-10

ARouter初始化及跳转原理

编译后生成文件

image-20210402085540859

仓库类

``

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<>();
    //省略部分代码
}

1.初始化代码追踪

ARouter.init(this);

进入ARouter.java

进入__ARouter.java

进入LogisticsCenter.java

``

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
    mContext = context;
    executor = tpe;

  //省略部分代码
            Set<String> routerMap;

            // It will rebuild router map every times when debuggable.
            //如果是debug模式,或者是新版本,则更新,否则直接从sp中获取
            if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
             		//关键代码1:获取“com.alibaba.android.arouter.routes”包名下的所有的class类名
             		//“com.alibaba.android.arouter.routes”即编译时生成的代码
                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 {
                routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
            }

						//进行实例化,只针对Root,Interceptor,provider
            for (String className : routerMap) {
                //com.alibaba.android.arouter.routes$$.ARouter$$Root
                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);
                }
            }
				}
}

1.首先通过包名获取包名下的class类名

2.反射进行实例化后,跳用loadInto,进行数据加载,将数据保存到Warehouse.groupsIndex

``

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Root$$app implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("demo", ARouter$$Group$$demo.class);
    routes.put("uri", ARouter$$Group$$uri.class);
  }
}

END

跳转

ARouter.getInstance().build(RouteConstant.LOGIN)
        .withString(LoginActivity.KEY_PATH, postcard.getPath())
        .navigation();

1.build

``

/**
 * Build postcard by path and default group
 */
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));
    }
}

如果有PathReplaceService,则进行路径替换。所以我们可以在项目中继承PathReplaceService来实现路径替换

``

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);
        }
        //关键代码 :创建Postcard对象。Postcard对象中包含了跳转所需要的class对象,参数等必须元素,此处只是设置了Postcard的path和group,其他属性的设置在navigation中完成
        return new Postcard(path, group);
    }
}

2.navigation

Postcard.java

``

public Object navigation() {
    return navigation(null);
}
public Object navigation(Context context) {
        return navigation(context, null);
    }
 public Object navigation(Context context, NavigationCallback callback) {
        return ARouter.getInstance().navigation(context, this, -1, callback);
    }

ARouter.java

``

public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
    return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
}

_ARouter.java

``

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
		//预处理服务
    PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
    if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
        // Pretreatment failed, navigation canceled.
        return null;
    }

    try {
      //关键代码,对postcard剩余字段进行赋值
        LogisticsCenter.completion(postcard);
    } catch (NoRouteFoundException ex) {
				//省略部分代码
        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);
    }
		//greenChannel = true 时拦截器不工作,eg: fragment 的greenChannel 为true
    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);
                }

                logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
            }
        });
    } else {
        return _navigation(context, postcard, requestCode, callback);
    }

    return null;
}

LogisiticsCenter.java

``

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.拿到group的class对象
        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 {
                 //省略代码
								/********************关键代码****************/
                //通过class对象进行初始化
                IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
              	//将要跳转的activity roteMeta数据加载到Warehouse.routes
                iGroupInstance.loadInto(Warehouse.routes);
                Warehouse.groupsIndex.remove(postcard.getGroup());
  							//省略代码
            } 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<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;
        }
    }
}

``

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:
            // Build intent
            final Intent intent = new Intent(currentContext, postcard.getDestination());
            intent.putExtras(postcard.getExtras());

            // Set flags.
            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);
            }

            // Set Actions
            String action = postcard.getAction();
            if (!TextUtils.isEmpty(action)) {
                intent.setAction(action);
            }

            // Navigation in main looper.
            runInMainThread(new Runnable() {
                @Override
                public void run() {
                    startActivity(requestCode, currentContext, intent, postcard, callback);
                }
            });

            break;

					//省略其他case
    return null;
}

End

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ARouter初始化及跳转原理 的相关文章

  • 带阴影的弯曲 Android 工具栏

    我需要为工具栏或卡片视图提供弯曲的底视图 我尝试过的 bg toolbar xml
  • Android 12:如何防止更改手机壁纸时重新启动活动?

    在 Android 12 上 如果我们开启一个活动 进入手机主屏幕更换壁纸 切换回我们的 Activity 该 Activity 重新启动 看起来它与 Material You 主题有关 我想在我的应用程序进入前台时禁用活动的重新启动 有办
  • 如何从另一个xml文件动态更新xml文件?

    我想从另一个 xml 文件更新 xml 文件 我使用了一个 xml 文件 如下所示 one xml
  • MI设备中即使应用程序被杀死,如何运行后台服务

    您好 我正在使用 alaram 管理器运行后台服务 它工作正常 但对于某些 mi 设备 后台服务无法工作 我使用了服务 但它无法工作 如何在 mi 中运行我的后台服务 MI UI有自己的安全选项 所以你需要的不仅仅是上面提到的粘性服务 你需
  • Google Inbox 类似 RecyclerView 项目打开动画

    目前 我正在尝试实现 Google Inbox 例如RecyclerView行为 我对电子邮件打开动画很好奇 我的问题是 该怎么做 我的意思是 他们使用了哪种方法 他们用过吗ItemAnimator dispatchChangeStarti
  • Android 手机应用意图

    我想在手机上启动手机应用程序作为意图 我正在使用这个代码 startActivity getPackageManager getLaunchIntentForPackage com android phone 但该函数抛出一个空指针异常 因
  • 如何检测 Google Play 上是否有我的应用程序的更新? [复制]

    这个问题在这里已经有答案了 有没有办法以编程方式检查 Google Play 上我的应用程序是否有更新 以便通知用户 我知道 android google play 有自动通知 但我想使用我自己的通知 弹出消息来更新可用性 有点像 Vibe
  • Cordova 地理定位不适用于 Android

    我想在 Android 上使用地理定位 我用 Apache Cordova 编写应用程序 地理定位在 android 电脑模拟器和 android 手机上均不起作用 I try http cordova apache org docs en
  • invalidateOptionsMenu 在片段中不起作用

    显示或隐藏项目ActionBar根据文本中是否有文本EditText or not 所以 我做了以下事情 public class NounSearch extends android app Fragment EditText seach
  • 版本 5 上带有 getBackground().setAlpha 的按钮 - 棒棒糖无法正常工作

    我有这段代码 适用于自 API 14 以来的每个版本 但在 Android 5 0 Lollipop 上无法正常工作 以下是我希望按钮出现的方式 单击按钮1 buttonArrivals getBackground setAlpha 180
  • Android:如何监控WiFi信号强度

    当信号强度发生变化时我会收到通知 我尝试创建以下方法并在 onCreate 中调用它 private void initializeWiFiListener Log i TAG executing initializeWiFiListene
  • 更改android中禁用按钮的颜色

    有没有办法通过样式或其他形式更改 android 中禁用按钮的颜色 我目前有以下内容 可绘制 button default xml
  • 点击监听器的公共类

    我的所有 6 项活动中有 7 个按钮 所有 6 个按钮在所有活动中都具有相同的功能 如何为这 6 个按钮执行通用的单击事件侦听器 您可以创建一个实现 View OnClickListener 的新类 如下所示 public class My
  • 带有空白白屏的 WebView

    我在 DialogFragment 中有一个 webview 它使用以下方式显示文档和 PDF它可以进行几次尝试 但如果用户尝试频繁打开和关闭对话框 webview 将显示空白屏幕 我已经尝试了所有的线程link1 https stacko
  • Google Android Drive api 在已安装版本上登录失败

    我开发了一个使用 GoogleDrive api 的 Android 应用程序 当处于调试状态或运行调试版本时 应用程序 工作正常 并正确验证附加的谷歌帐户 等 当我构建发行版本时 使用我的签名密钥 并且 安装apk文件 当我运行时 Goo
  • 按名称查找视图

    是否可以通过名称而不是 id 来查找视图 findViewById R id someView 但我想做这样的事情 findViewByName someView 在处理 xml 时 您必须通过标识符查找视图 但是您可以使用以下方式查找标识
  • 如何使 tablayout 文本大小相等?

    这就是我所做的 我为文本创建了一种样式
  • WebView 在某些设备上如果不长按则不会滚动

    我有一个 WebView 设置如下 the web view mWebView WebView findViewById R id webView push the url on to the web view mWebView loadU
  • Android应用程序kill事件捕获

    我想在我的应用程序被终止时执行一些操作 可以使用哪种方法来实现此目的 我正在开发 Android 5 0 这个问题的关键在于 您必须了解您的申请是否可以收到任何 当您的应用程序在任何情况下被终止时的额外回调 下面的答案是由德文连线 http
  • 修改 ADW Android 启动器?

    我想更改和修改开源 ADW 启动器 启动器可在此处获取 https github com AnderWeb android packages apps Launcher https github com AnderWeb android p

随机推荐

  • 第三章部分作业重新调试结果(第五周)

    求 百钱百鸡 问题 鸡翁一值钱五 鸡母 一值钱三 鸡雏三值钱一 百钱买百鸡 问鸡翁 鸡母 鸡雏各几何 设买了x只鸡翁 y只鸡目 z只鸡雏 则有 x y z 100 5 x 3 y 1 3 z 100 15 x 9 y z 300 inclu
  • 变分贝叶斯

    Variational Bayesian inference 参考文献 徐亦达老师变分推断课件 A tutorial on variational Bayesian inference 白板推导指数族分布 白板推导变分推断 Log like
  • 实测最像ChatGPT的中文产品:能解释三体、懂弱智吧的梗,内测开启人人都能试!...

    明敏 发自 凹非寺量子位 公众号 QbitAI 最像ChatGPT的中文产品 出现了 昨晚 一个名叫Inspo的生成式对话AI 刚刚在 民间 开启内测 马上引发不小反响 体验过的博主表示 1分钟搞定3份策划 工作5年没它能写 有人自己上手试
  • IP数据报检验和计算

    在进行计算之前先补充一下基础知识 一 原码 反码和补码 原码 原码是计算机机器数中最简单的一种形式 数值位就是真值的绝对值 符号位位 0 时表示正数 符号位为 1 时表示负数 原码又称带符号的绝对值 为了方便整数和小数区别 整数的符号位与数
  • Android 实现按钮 跳转到某网页

    这个是我在刚开始学习Android的时候 我同学要做一个手机端的控制 他说我的东西都用 java web写好了 你只要给我写一个跳转按钮即可 其实很简单只是简单地按钮点击事件和Intent跳转 但是毕竟是第一次帮别人做东西还觉得挺有意义的
  • YouTube深度学习视频推荐系统

    YouTube推荐系统架构 YouTube推荐系统架构是经典的两级模型 召回 精排模型 第一级用候选集生成模型完成候选视频的快速筛选 在这一步 候选视频集合由百万量级降至几百量级 这相当于经典推荐系统架构中的召回层 第二级用排序模型 Ran
  • 【mac】iTerm2中ssh保持连接不断开

    1 概述 转载 http bluebiu com blog iterm2 ssh session idle html 一 一个iTerm2蛋疼的问题 最近基友搞了台mbp 在装一些常用app时 跟我交流到一个情况 用iTerm2进行ssh时
  • 树莓派串口调试助手minicom的简单使用

    安装 minicom sudo apt get install minicom 启动minicom minicom D dev ttyAMA0 minicom 默认波特率为115200 D 代表端口 b 设置波特率参数 例如 b 9600
  • 网络调试工具TCP/UDP socket的使用

    TCP UDP socket调试工具的使用 可以在想服务器发送命令 或者查看服务器返回的数据 打开界面后选择左边客户端还是服务端 使用TCP还是udp 点击创建相应的模拟环境
  • docker 容器满了常用处理方法

    docker 容器满了常用处理方法 1 运行 df h 查看剩余磁盘占用情况 2 进入到docker目录 cd var lib docker 3 运行du h max depth 1 检索文件的最大深度1 即只检索汇总计算当前目录下的文件
  • Oracle用function生成UUID方法

    CREATE OR REPLACE FUNCTION get uuidRETURN VARCHARISguid VARCHAR 50 BEGINguid lower RAWTOHEX sys guid RETURNsubstr guid 1
  • 移动端/帆软移动报表调用拨打电话

    HTML a标签的href 属性 tel 点击可以直接拨打电话 移动端 a href 13622178579 a 把某个单元格 形态赋值为 公式形态 a href style color 508ef9 a ps F1列存储电话号码
  • 自动化运维脚本语言shell练习(2)

    1 编写脚本for1 sh 使用for循环创建20账户 账户名前缀由用户从键盘输入 账户初始密码由用户输入 例如 test1 test2 test3 test10 2 编写脚本for2 sh 使用for循环 通过ping命令测试网段的主机连
  • 程序员,你今年读了几本书?

    调查显示 国人去年平均阅读 4 本书 程序员不应该只有 代码大全 4 23 世界读书日 GitChat 码农读书日 活动最后 1 天 用抄底的价格 抢你要的技术书 GitChat 特意筛选畅销度最高的品种 给予超大力度的优惠 深度学习入门
  • 如何关闭FileZilla Server开机自启

    FileZilla Server开机自启 有些软件开机自启 个人感觉是比较反感的 像流氓一样 如何关闭 选中此电脑 gt 右键单击 gt 点击管理 找到之后FileZilla Server FTP server之后右键点击属性 改成手动启动
  • 重t2加权是什么意思_王者荣耀中说的T0、T1,到底是啥意思?这下总算清楚了

    王者荣耀这款游戏可以说是相当火了 玩这款游戏的人应该有3亿左右了吧 而在这么庞大的人群中 也孕育出一种独特的语言 甚至有些老玩家也是没有听说过得 就比如今天我们要聊的 在王者荣耀中说的TO T1到底是什么意思呢 今天就给大家科普一下 TO英
  • testflight测试的直播软件,怎么使用 TestFlight 测试 App,注意些什么?

    原标题 怎么使用 TestFlight 测试 App 注意些什么 TF签名是什么 TF签名全称为TestFlight 实际为一个苹果官方研发的一款提供给ios开发者内测的一个工具类App 这款app可以在苹果商店搜索到 用户直接搜索打开Te
  • java 图形与动画_如何优化java动画编程中的显示效果

    展开全部 Java动画编62616964757a686964616fe4b893e5b19e31333264623234程有多种实现方法 但它们实现的基本原理是一样的 即在屏幕上画出一系列的帧来造成运动的感觉 Java多线程技术是Java动
  • C++——STL库中迭代器以及其代码实现简介

    文章目录 一 STL库中迭代器的简介 1 迭代器的定义 2 迭代器常用的运算 3 vector和deque提供的额外运算 4 迭代器的取值范围 二 STL库中迭代器的代码实现 总结 一 STL库中迭代器的简介 1 迭代器的定义 迭代器 it
  • ARouter初始化及跳转原理

    ARouter初始化及跳转原理 编译后生成文件 仓库类 class Warehouse Cache route and metas static Map