我的学习手册 - ARouter了解了一下下

目录

我的学习手册 - 热更新了解了一下下
我的学习手册 - Glide了解了一下下
我的学习手册 - 进程保活了解了一下下
我的学习手册 - EventBus了解了一下下
我的学习手册 - ARouter了解了一下下

首先了解页面Activity跳转,只要获取到了clazz对象,那么所有的Activity都可以跳转

    startActivity(mContext,clazz)

简单思路:

  • 首先在底层模块中需要一个存放key和value的map,用于存放地址和Activity的class对象,

  • 然后在每一个需要跨模块跳转的添加地址和class存入方法的工具类

  • 之后App模块集成所有Module,在App模块中在合适的地方调用每一个Module的这些个方法工具类,就把需要的Activity的Class对象存入了

  • 最后在需要调用的地方将需要的Activity的Class对象取出

进阶思路:

  • 通过注解和注解处理器,将所有添加注解的Activity的path和class通过文件生成器自动生成,生成的文件需要固定使用同一个包名,但是文件名不能一样,这里生成的文件全部实现一个统一接口,这样会方便调用
  • 之后在初始化的时候通过反射获取该包名下的所有类,并且实例化调用统一方法
一、ARouter工具
    // 需要一个Map 存放当前App中所有需要跳转的Activity的Class对象
    private val activityMap: HashMap> = hashMapOf()
    
    /*** 将地址和Activity的Class对象存入 ***/
    fun setActivityClazz(path: String, clazz: Class) {
        if (path.isNotEmpty()) {
            activityMap.put(path, clazz)
        }
    }

    /*** 读取存放的Activity ***/
    fun getActivityClazz(path: String): Class? {
        return activityMap[path]
    }
二、IRouter公共接口
interface IRouter {
    fun putActivity()
}
三、底层路径
object RouterPath{
    const val MemberActivity = "/Member/MemberActivity"
    const val NewsActivity = "/News/NewsActivity"
}
四、Module数据存入

将Router模块依赖到app和其他需要跳转的所有module,在每一个需要跳转的module中创建一个ModuleRouter工具实现IRouter,这个时候可以获取到需要跳转的Class对象,存入ARouter组件中,例如:

object MemberRouter : IRouter {
    
    override fun putActivity() {
        ARouter.get().setActivityClazz(RouterPath.MemberActivity, MemberActivity::class.java)
    }
}
五、App中的数据存入与获取
    // 在合适的地方进行调用 存入所有模块中需要跳转的Activity对象
    MemberRouter.putActivity()
    NewsRouter.putActivity()
   
    // 在Member模块中跳转到News模块中
    val clazz = ARouter.get().getActivityClazz(RouterPath.NewsActivity)
    startActivity(Intent(this,clazz))

到这里一个简单的路由组件的实现就完成了,基本思路就是通过中间件来存入和获取需要跳转的Activity的Class对象

六、进阶-注解 仿照ARouter
1、创建注解

创建Kotlin Library (annotaion)

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class Route(val path: String)
2、创建注解处理器

创建Kotlin Library (annotation_compiler)

我的AS是3.6.2都加上才会进行处理
implementation 'com.google.auto.service:auto-service:1.0-rc6'
kapt 'com.google.auto.service:auto-service:1.0-rc6'

// 自动注册
@AutoService(Processor::class)
// 表示使用Java8和build.gradle中保持同步
@SupportedSourceVersion(SourceVersion.RELEASE_8)
// 只进行解析Route注解
@SupportedAnnotationTypes("com.memo.annotation.Route")
class RouteCompiler : AbstractProcessor() {
    
    /*** 文件生成器 ***/
    lateinit var filer: Filer
    /*** 日志打印 ***/
    lateinit var logger: Messager

    /*** 初始化 ***/
    override fun init(environment: ProcessingEnvironment) {
        super.init(environment)
        filer = environment.filer
        logger = environment.messager
    }

    /*** 处理生成代码文件 ***/
    override fun process(set: MutableSet, environment: RoundEnvironment): Boolean {
        // 拿到Route注解的节点
        // 有三种注解节点  类节点TypeElement 方法节点ExecutableElement 变量节点VariableElement
        val routeSets = environment.getElementsAnnotatedWith(Route::class.java)
        // 存放path和activity
        val activityMap = HashMap()
        routeSets.forEach {
            val typeElement = it as TypeElement
            // 地址
            val path = typeElement.getAnnotation(Route::class.java).path
            // Activity全路径
            val activityName = typeElement.qualifiedName.toString()
            // 把地址和Activity的带包名的地址存入
            activityMap[path] = activityName

            logger.printMessage(Diagnostic.Kind.WARNING, "发现路由组件-->$activityName")
        }

        // 生成文件
        if (activityMap.isNotEmpty()) {
            // 生成唯一的文件名称 防止文件重复 有多个Module多次调用
            // 按照ARouter这里是module名称拼接 偷懒了
            val fileName = "RouterUtils_${System.currentTimeMillis()}"
            try {
                // 创建文件
                // 使用use方法自动关闭io流
                filer.createSourceFile(fileName).openWriter().use {
                    it.write(createFileContent(fileName, activityMap))
                }
            } catch (e: Exception) {
                logger.printMessage(Diagnostic.Kind.ERROR, e.toString())
            }

        }

        return false
    }


    /**
     * 创建Java文件内容
     * 这里可以使用JavaPoet或者KotlinPoet代替 依赖相应的包
     * 我用的不熟练所以就直接字符串拼接了
     */
    private fun createFileContent(fileName: String, activityMap: HashMap): String {
        val buffer = StringBuffer()
        buffer.append(
            "package com.memo.router.utils;\n" +
                    "import com.memo.router.core.ARouter;\n" +
                    "import com.memo.router.core.IRouter;\n" +
                    "public class $fileName implements IRouter {\n" +
                    "@Override\n" +
                    "public void putActivity() {\n"
        )
        activityMap.forEach { (path, activity) ->
            buffer.append("ARouter.get().setActivityClazz(\"$path\", $activity.class);\n")
        }
        buffer.append("}\n}")
        return buffer.toString()
    }
}
3、调用putActivity方法

在初始化的时候可以传入ApplicationContext,利用这个进行页面跳转
之前我们在写文件的时候是固定包名的com.memo.router.utils,那么我们可以通过反射来找到对应包名下面的所有文件,ClassUtils直接从Arouter中CV过来

        val files = ClassUtils.getFileNameByPackageName(mContext, "com.memo.router.utils")
        files.forEach {
            try {
                val clazz = Class.forName(it)
                // 查看是否实现了IRouter
                if (IRouter::class.java.isAssignableFrom(clazz)) {
                    // 开始调用putActivity方法
                    (clazz.newInstance() as IRouter).putActivity()
                }
            } catch (e: Exception) {
            }
        }
4、添加注解并且跳转
    /*** 通过ApplicationContext 直接跳转 ***/
    fun startActivity(path: String, bundle: Bundle? = null) {
        val clazz = activityMap[path]
        clazz?.let {
            val intent = Intent(mContext, it)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            if (bundle != null) intent.putExtras(bundle)
            mContext.startActivity(intent)
        }
    }
    
    ARouter.get().startActivity(RouterPath.NewsActivity)
源码

最后放上源码地址 ARouter了解了一下下

你可能感兴趣的:(我的学习手册 - ARouter了解了一下下)