• Android组件化神器 --- ARouter


    组件,就是对数据和方法的简单封装,功能单一,高类聚,是业务划分的最小粒度。组件化是基于可重用的目的,将大型软件系统按照分离关注点的形式,拆分成多个独立组件,使得整个软件是单个或多个组件元件组装起来。那组件之间如何通信呢?这就得益于ARouter。

    Android原生的路由方案是Intent的显式和隐式跳转,显式需要对目标的引用,会导致不同页面的耦合,隐式集中配置在manifest中,不利于维护和管理。况且,在组件化开发中,各模块之间无法直接引用,那么,ARouter路由框架就派上用场了。

    一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦

    原理简述

    ARouter通过APT技术,生成保存路径(路由path)和被注解(@Router)的组件类的映射关系的类,利用这些保存了映射关系的类,根据用户的请求postcard寻找到要跳转的目标地址,使用Intent跳转。所以,该框架的核心是利用APT生成的映射关系,APT的作用是在编译阶段扫描并处理代码中的注解,然后根据注解输出Java文件。

    基本使用

    添加依赖和配置,注意,每个使用到ARouter的Module都要引入

    plugins {
        id 'com.android.library'
        id 'org.jetbrains.kotlin.android'
        id 'kotlin-kapt'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
        kapt {
            arguments {
                arg("AROUTER_MODULE_NAME", project.getName())
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
        implementation 'com.alibaba:arouter-api:1.5.2'
        kapt 'com.alibaba:arouter-compiler:1.5.2'
    
    • 1
    • 2

    引入后需要注意的一点是:要在gradle.properties文件中加入下面这个,不然会编译不过去,这也是我遇到的一个小坑。

    android.enableJetifier=true
    
    • 1

    在Application中初始化

            if (isDebug()) {
                ARouter.openLog() //打印日志
                ARouter.openDebug() //开启调试模式,线上需关闭
            }
            ARouter.init(this)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在支持路由的页面上添加如下注解,路径至少需要两级

    @Route(path = "/home/HomeActivity")
    class HomeActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_home)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    然后在另一个Activity中,进行跳转

    ARouter.getInstance().build("/home/HomeActivity").navigation()
    
    • 1

    如果需要传递参数的话,可以这样做

                ARouter.getInstance().build("/home/HomeActivity")
                    .withString("name", "Uncle Xing")
                    .withInt("age", 25)
                    .withSerializable("user", User("Uncle Xing", 25))
                    .navigation()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    然后在目标Activity中通过Autowired接收,ARouter会自动对字段进行赋值,无需主动获取

    @Route(path = "/home/HomeActivity")
    class HomeActivity : AppCompatActivity() {
    
        @JvmField
        @Autowired
        var name = ""
    
        @JvmField
        @Autowired
        var age = 0
    
        @JvmField
        @Autowired
        var user: User? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_home)
            initView()
        }
    
        private fun initView() {
            ARouter.getInstance().inject(this)
            
            findViewById<TextView>(R.id.name).text = name
            findViewById<TextView>(R.id.age).text = age.toString()
            findViewById<TextView>(R.id.user).text = user.toString()
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在组件化开发中,我们通常会有一些公共Module来作为共有功能,那这个时候就可以使用ARouter的依赖注入解耦,组件件的通信,首先我们要声明接口,其他组件通过这个接口来调用方法

    interface MyProvider : IProvider {
        fun getData(): String
    }
    
    • 1
    • 2
    • 3

    实现类

    @Route(path = "/common/MyProviderImpl")
    class MyProviderImpl : MyProvider {
        override fun getData(): String {
            return "Welcome to my blog"
        }
    
        override fun init(context: Context?) {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    其他组件的Activity就可以这样调用

    class MainActivity : AppCompatActivity() {
    
        /**
         * 当一个接口只有一个实现类的时候,Autowired可以不设置name
         */
        @JvmField
        @Autowired(name = "/common/MyProviderImpl")
        var myProvider: MyProvider? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            initView()
        }
    
        private fun initView() {
            ARouter.getInstance().inject(this)
            findViewById<TextView>(R.id.provider_text).text = myProvider?.getData()
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    上面是使用依赖注入的方式,通过注解标注字段,即可使用,无需主动获取,除此之外,我们也可以使用赖查找的方式,比如上面的代码我们也可以写成这样

    class MainActivity : AppCompatActivity() {
    
        var myProvider: MyProvider? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            initView()
        }
    
        private fun initView() {
    //        ARouter.getInstance().inject(this) 这种方式不需要这句
            myProvider =
                ARouter.getInstance().build("/common/MyProviderImpl").navigation() as MyProvider
            /**
             * 发现的方式有byName和byType,如果一个接口只有一个实现的话,也可以使用byType,可以写成
             *  myProvider = ARouter.getInstance().navigation(MyProvider::class.java)
             */
            findViewById<TextView>(R.id.provider_text).text = myProvider?.getData()
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    我们也可以动态注册路由,这样,目标页面和服务就可以不标注 @Route 注解。不过,一般组件化项目都不会这样干,适合部分插件化架构的项目或其他场景。

            ARouter.getInstance().addRouteGroup {
                it["/home/HomeActivity"] = RouteMeta.build(
                    RouteType.ACTIVITY,       //路由信息
                    HomeActivity::class.java, //目标class
                    "/home/HomeActivity", //path
                    "home",              //Group,尽量保持和path的第一段相同
                    0, 0
                )
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意:同一批次仅允许相同 group 的路由信息注册

  • 相关阅读:
    ARM通用中断控制器GIC(generic Interrupt Controller)简介
    微信网页版登录插件v1.1.1
    【C++】之类和对象 - static静态成员
    搭建C语言的环境
    RK3568 Ubuntu终端无法打开问题
    人人商城app禁用
    汇编精讲02
    Java进阶常用的辅助类(CountDownLatch 减法计数器、CyclicBarrier 加法计数器、Semaphore 信号量)
    SpringCloudGateWay个人笔记
    DNS外带注入
  • 原文地址:https://blog.csdn.net/qq_45485851/article/details/126282874