TheRouter 框架原理

TheRouter 框架入口方法

通过InnerTheRouterContentProvider 注册在AndroidManifest.xml中,在应用启动时初始化

    <application>
        <provider
            android:name="com.therouter.InnerTheRouterContentProvider"
            android:authorities="${applicationId}.therouter.TheRouteContentProvider"
            android:exported="false" />
    </application>

入口方法为TheRouter.init(applicationContext)

class InnerTheRouterContentProvider : ContentProvider() {
    override fun onCreate(): Boolean {
        applicationContext ?: let {
            applicationContext = context
        }
        if (theRouterUseAutoInit) {
            TheRouter.init(applicationContext)
            debug("InnerTheRouterContentProvider", "TheRouter auto init in Application")
        }
        return true
    }

    override fun query(uri: Uri, strings: Array<String>?, s: String?, strings1: Array<String>?, s1: String?): Cursor? {
        return null
    }

    override fun getType(uri: Uri): String? {
        return null
    }

    override fun insert(uri: Uri, contentValues: ContentValues?): Uri? {
        return null
    }

    override fun delete(uri: Uri, s: String?, strings: Array<String>?): Int {
        return 0
    }

    override fun update(uri: Uri, contentValues: ContentValues?, s: String?, strings: Array<String>?): Int {
        return 0
    }
}

    /**
     * TheRouter初始化方法。内部流程:<br>
     * 同步流程:<br>
     *     1. 首先初始化FlowTask的内置事件,BEFORE_THEROUTER_INITIALIZATION,以及依赖这个Task的全部任务。
     *         这个事件的目的是在TheRouter的路由初始化前做某些操作,例如修改路由表、添加路由拦截器等……
     *     2. 初始化跨模块依赖表
     *     3. 初始化路由表
     * 异步流程:<br>
     *     1. 调用FlowTask的外部事件
     *     2. 添加 @Autowired 路由解析器
     */
    @JvmStatic
    fun init(context: Context?) {
        if (!inited) {
            ......
            addFlowTask(context, digraph)
            ......
        }
    }

在初始化前先调用addFlowTask(context, digraph)方法。

在跳转到对应方法实现处发现,该方法为空方法,没有具体业务逻辑。

@file:JvmName("TheRouterServiceProvideInjecter")

package a

import android.content.Context
import com.therouter.flow.Digraph

/**
 * Created by ZhangTao on 18/2/24.
 */
fun trojan() {}
fun autowiredInject(obj: Any?) {}
fun addFlowTask(context: Context?, digraph: Digraph) {}
fun initDefaultRouteMap() {}

在学习了相关博客后,发现这里暗藏了TheRouter设计的巧妙之处,也正是因为这个特点,TheRouter框架在没有使用反射机制情况下,可以动态注入逻辑。

我们在按照TheRouter框架添加了各种注解后,在编译期间,会自动生成一个合成类,将我们添加了@FlowTask(taskName = "xxx")注解的方法全部放到一个静态public static void addFlowTask(android.content.Context context, com.therouter.flow.Digraph digraph)方法中。

Debug 时,编译器生成的对应合成文件在目录

编译时生成对应方法如下

	public static void addFlowTask(android.content.Context context, com.therouter.flow.Digraph digraph) {
		digraph.addTask(new com.therouter.flow.Task(false, "base_init", "", new com.therouter.flow.FlowTaskRunnable() {
			@Override
			public void run() {
				com.ugreen.modulesbase.base.BaseInitTaskKt.initBase(context);
			}

			@Override
			public String log() {
				return "com.ugreen.modulesbase.base.BaseInitTaskKt.initBase(context);";
			}
		}));
		digraph.addTask(new com.therouter.flow.Task(false, "init_device_info", "base_init", new com.therouter.flow.FlowTaskRunnable() {
			@Override
			public void run() {
				com.ugreen.modulesbase.base.BaseInitTaskKt.initDeviceInfo(context);
			}

			@Override
			public String log() {
				return "com.ugreen.modulesbase.base.BaseInitTaskKt.initDeviceInfo(context);";
			}
		}));
		digraph.addTask(new com.therouter.flow.Task(false, "base_init_language", "", new com.therouter.flow.FlowTaskRunnable() {
			@Override
			public void run() {
				com.ugreen.modulesbase.base.BaseInitTaskKt.initLanguage(context);
			}

			@Override
			public String log() {
				return "com.ugreen.modulesbase.base.BaseInitTaskKt.initLanguage(context);";
			}
		}));
		digraph.addTask(new com.therouter.flow.Task(false, "base_init_smartRefresh", "", new com.therouter.flow.FlowTaskRunnable() {
			@Override
			public void run() {
				com.ugreen.modulesbase.base.BaseInitTaskKt.initSmartRefresh(context);
			}

			@Override
			public String log() {
				return "com.ugreen.modulesbase.base.BaseInitTaskKt.initSmartRefresh(context);";
			}
		}));
		digraph.addTask(new com.therouter.flow.Task(false, "base_init_titleBar", "", new com.therouter.flow.FlowTaskRunnable() {
			@Override
			public void run() {
				com.ugreen.modulesbase.base.BaseInitTaskKt.initTitleBar(context);
			}

			@Override
			public String log() {
				return "com.ugreen.modulesbase.base.BaseInitTaskKt.initTitleBar(context);";
			}
		}));
	}

这个方法名是不是很熟悉,只看它的方法名和入参数,这和前面提到的空方法一模一样。

是的,你没有看错,这里编译期间生成的方法就是要通过字节码插桩技术替换空方法实现。

是不是很巧妙。

那么接着看TheRouter的init方法,开始执行digraph.beforeSchedule()方法

    /**
     * 由于initSchedule执行比较耗时需要放到异步,而Before需要在路由表初始化之前执行,需要同步
     * 所以单独列出一个方法,检测dependsOn只有beforTheRouterInit的任务,提前执行
     */
    fun beforeSchedule() {
        val virtualFlowTask = getVirtualTask(TheRouterFlowTask.BEFORE_THEROUTER_INITIALIZATION)
        virtualTasks[TheRouterFlowTask.BEFORE_THEROUTER_INITIALIZATION] = virtualFlowTask
        virtualFlowTask.run()

        tasks.values.forEach {
            if (!it.async && it.dependencies.size == 1
                && it.dependencies.contains(TheRouterFlowTask.BEFORE_THEROUTER_INITIALIZATION)
            ) {
                // 此时一定在主线程,所以直接调用
                it.run()
            }
        }
    }

该方法同步执行,首先检测出dependsOn为beforTheRouterInit的任务,开始执行

查看源码发现,即使接入端未添加该dependsOn注解,这里也会默认创建一个virtualTask任务,这里不是很理解,后续补充。

beforeSchedule在执行完成virtualFlowTask后,开始执行依赖该task的任务,这里过滤条件要求,任务为同步执行且只依赖beforTheRouterInit的任务列表。

 接着看TheRouter的init方法,通过execute执行一个异步的代码片段

            execute {
                debug("init", "TheRouter.init() method do @FlowTask init")
                digraph.initSchedule()
                debug("init", "TheRouter.init() method do @FlowTask schedule")
                runInitFlowTask()
            }

initSchedule具体内容如下

    /**
     * 初始化方法
     */
    fun initSchedule() {
        for (task in tasks.values) {
            fillTodoList(task)
        }
        inited = true
        pendingTaskRunnableList.forEach {
            it.run()
        }
    }

这里重点方法如下

    private fun fillTodoList(root: Task) {
        if (!root.isDone()) {
            val dependsSet = getDepends(root)
            if (isNotEmpty(dependsSet)) {
                if (loopDependStack.contains(root)) {
                    throw IllegalArgumentException(
                        "TheRouter::Digraph::Cyclic dependency " + getLog(
                            loopDependStack,
                            root
                        )
                    )
                }
                loopDependStack.add(root)
                for (depend in dependsSet) {
                    fillTodoList(depend)
                }
                loopDependStack.remove(root)
                if (!todoList.contains(root)) {
                    todoList.add(root)
                }
            } else {
                if (!todoList.contains(root)) {
                    todoList.add(root)
                }
            }
        }
    }

通过递归调用将task依赖任务转化成一个todoList队列里面,这样就能保证被依赖的task放在队列的前面,依赖的放置在队列后面。关于这个队列具体如何作用后续继续说明

继续回到execute 代码片段里,继续执行runInitFlowTask方法

/**
 * 当TheRouter初始化时,执行的FlowTask
 */
fun runInitFlowTask() {
    TheRouter.runTask(TheRouterFlowTask.THEROUTER_INITIALIZATION)
}

接着继续查看Init方法,执行routerInject.asyncInitRouterInject(context)方法

该方法就是将路由相关的进行注入,例如配置的路由拦截器和自定义的拦截器

在asyncInitRouterInject方法中,判断mInterceptors为空时会从dex 文件中解析对应的拦截器,并实例化放入到mInterceptors对象里面,mInterceptors = TheRouterLinkedList<Interceptor>(16),最终也就是放入到该列表中,这里最多支持16个拦截器对象

    fun asyncInitRouterInject(context: Context?) {
        execute {
            trojan()
            if (mInterceptors.isEmpty()) {
                initServiceProvider(context)
            }
        }
    }

继续接着执行Init方法,开始执行asyncInitRouteMap()方法,该方法主要是用来加载路由配置

/**
 * 在异步初始化路由表
 */
fun asyncInitRouteMap() {
    execute {
        debug("RouteMap", "will be add route map from: initDefaultRouteMap()")
        initDefaultRouteMap()
        initedRouteMap = true
        if (initTask == null) {
            initRouteMap()
        } else {
            debug("RouteMap", "will be add route map from: RouterMapInitTask")
            initTask?.asyncInitRouteMap()
        }
        executeInMainThread {
            sendPendingNavigator()
        }
    }
}

这里为异步执行,首先执行一个initDefaultRouteMap的空方法,这里也应该是在编译期间通过字节码插桩替换,不过这里没有发现具体逻辑。

如何initTask为空,也就是前面空方法没有具体业务实现,那么这里就会从assets资源目录里面读取对应的路由配置,assets目录下var ROUTE_MAP_ASSETS_PATH = "therouter/routeMap.json" 在编译时会生成这样一个json文件

接着回来继续执行Init方法

            execute {
                context?.apply {
                    (applicationContext as Application).registerActivityLifecycleCallbacks(TheRouterLifecycleCallback)
                }
                parserList.addFirst(DefaultObjectParser())
                parserList.addFirst(DefaultServiceParser())
                parserList.addFirst(DefaultUrlParser())
                parserList.addFirst(DefaultIdParser())
            }

这里注册全局的Activity生命周期监听,注册各种解析器,在编译期间根据添加@Autowired注解进行代码生成

这里使用不是很理解,后面补充。

以上就是TheRouter Init方法整体初始化流程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。
TheRouter 和 ARouter 都是 Android 平台上常用的路由框架,用于实现组件之间的通信和页面跳转。下面是对 TheRouter 和 ARouter 的简要比较: 1. TheRouter: - TheRouter 是一个基于 Android 平台的轻量级路由框架,用于实现模块化和解耦合的架构。 - 它提供了简单而灵活的 API,通过注解配置路由信息,并支持页面跳转和参数传递等功能。 - TheRouter 支持拦截器机制,可以在页面跳转前或后执行自定义的逻辑。 - 它具有生命周期管理功能,可以与 Activity 或 Fragment 的生命周期进行绑定。 - TheRouter 的代码库相对较小,易于集成和使用。 2. ARouter: - ARouter 是阿里巴巴开源的 Android 路由框架,具有强大的功能和广泛的社区支持。 - 它支持通过注解配置路由信息,并提供了丰富的 API,用于实现页面跳转、参数传递、拦截器等功能。 - ARouter 提供了多种路由方式,包括普通路由、自动路由和隐式路由等。 - 它支持 URL 路由,可以通过 URL 地址进行页面跳转。 - ARouter 提供了强大的参数传递功能,支持自动解析和自定义传递参数。 - 它具有强大的插件化支持,可以在编译时生成路由表,提高运行时的效率。 选择使用 TheRouter 还是 ARouter 取决于你的具体需求和偏好。如果你需要一个轻量级的库,更注重简洁的 API 和易用性,可以考虑使用 TheRouter。如果你需要更丰富的功能、强大的社区支持和插件化能力,同时不介意稍微复杂一些的集成和配置,那么 ARouter 也是一个很好的选择。 无论选择哪个框架,它们都可以帮助你实现组件之间的解耦和灵活的通信,提高项目的可维护性和扩展性。 希望对你有所帮助!如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值