组件化开发Aroute原理简析

android 模块化开发与ARoute之间不得不说的坑 模块化开发因为其合理的解耦性广受青睐,现在关于模块化开发的框架demo已经很多了,对于不同模块之间的跳转也各有各的独门秘方,我用的是阿里的ARoute,这个在GitHub上star已经有9k+了 一、集成: 1、需要在用到ARoute的每一个module中都添加以下配置 android { defaultConfig { ...... 阅读详情

对组件化开发的基本认识中,各个模块之间的通讯方式明显不能满足项目需求,此时就需要一个通讯框架实现模块之间的通讯。框架的意义就在于实现解耦的前提下,能够让各组件之间完成通讯。所以简单学习了一个Aroute框架权当记录,错误的地方还请指正

本demo设置了主程序和登录模块,一些基本的配置,例如library开关,manifest设置等本文就不再描述,直接简述Aroute的流程

创建ArouteLibrary依赖库,让主程序和登录模块依赖此项目

public class Aroute {
//    存放key和对应activity的map
    private Map<String, Class<? extends Activity>> maps;
//    上下文对象
    private Context context;
//  初始化上下文,遍历整个apk中类,找到放入ActivityUtil类,执行往map中放入activity的方法
    public void init(Context context) {
        this.context = context;
//        获取com.syw.util包下所有的类
        List<String> classNames = getClassName("com.syw.util");
        for (String className : classNames) {
            try {
//                通过反射获取类
                Class<?> aClass = Class.forName(className);
//                判断该类是否是IRouter的子类
                if (IRouter.class.isAssignableFrom(aClass)) {
//                  创建类对象
//					IRouter接口包含putActivity方法,由注解处理器生成的代码重写,具体实现添加k-v到map中。规范代码,方便统一调用
                    IRouter iRouter = (IRouter) aClass.newInstance();
//                    执行类对象中putActivity方法,将所有有注解的类加入到map中
                    iRouter.putActivity();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public Aroute() {
//        在Aroute初始化的时候,创建map
        maps = new HashMap<>();
    }

    public static Aroute instance = new Aroute();

    public static Aroute getInstance() {
        return instance;
    }

    /**
     * 将有注解的类存入map
     * @param key 注解内容
     * @param clazz 该注解对应的类
     */
    public void addActivity(String key, Class<? extends Activity> clazz) {
        if (key != null && clazz != null && !maps.containsKey(key)) {
            maps.put(key, clazz);
        }
    }

    /**
     * 根据用户传入的key,找到类,完成跳转
     * @param key
     * @param bundle
     */
    public void jumpActivity(String key, Bundle bundle) {
        Class<? extends Activity> activityClass = maps.get(key);
        if (activityClass != null) {
            Intent intent = new Intent(context, activityClass);
            if (bundle != null) {
                intent.putExtras(bundle);
            }
            context.startActivity(intent);
        } 
    }

    /**
     * 获取所有指定包名下的类
     * @param packageName
     * @return
     */
    private List<String> getClassName(String packageName) {
        List<String> classList = new ArrayList<>();
        String path = null;
        try {
//            获取apk的完整路径
            path = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0).sourceDir;
//            根据apk路径获取编译后的dex文件目录
            DexFile dexFile = new DexFile(path);
//            获取编译后dex文件中的所有class
            Enumeration<String> entries = dexFile.entries();
//            遍历当前应用所有文件class
            while (entries.hasMoreElements()) {
                String name = entries.nextElement();
                if (name.contains(packageName)) {
//                    如果符合就添加到集合
                    classList.add(name);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return classList;
    }
}

编写注解和注解处理器

Aroute用到的是apt技术,也就是编译时技术。在编译期执行,包括注解和注解处理器

注解

我们可以自定义注解,对类/方法等进行标记
新建一个java依赖库,创建一个类对象

@Target(ElementType.TYPE)//TYPE表示该注解放到类上边,@Override放到方法上,@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)//表示生命周期存在于编译期,代码有源码期--编译期--运行期,Override是源码期,所以编译后的代码,没有@Override
public @interface BindPath {
//    用于获取注解中的内容
    String value();
}
注解处理器

本demo中注解处理器的作用是:在编译期在指定目录下,在各个模块生成我们想要的java代码。
新建一个java依赖库,依赖注解模块,创建一个注解处理器类

//向javac注册我们这个自定义的注解处理器,这样,在javac编译时,才会调用到我们这个自定义的注解处理器方法。
//AutoService这里主要是用来生成META-INF/services/javax.annotation.processing.Processor文件的。
//使用AutoService需要添加以下依赖
// as 3.4以上版本
//    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
//    compileOnly 'com.google.auto.service:auto-service:1.0-rc3'
// as 3.4以下版本
//    implementation 'com.google.auto.service:auto-service:1.0-rc3'
@AutoService(Processor.class)
public class AnnotationCompiler extends AbstractProcessor {
    Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        filer = processingEnvironment.getFiler();
    }

    @Override
    // 获取java版本
    public SourceVersion getSupportedSourceVersion() {
        return processingEnv.getSourceVersion();
    }

    @Override
    //设置该处理器能处理的节点,必须是注解的全类名
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new HashSet<>();
        types.add(BindPath.class.getCanonicalName());
        return types;
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//        查看该项目下的BindPath节点集合
        Set<? extends Element> elementsAnnotateWith = roundEnvironment.getElementsAnnotatedWith(BindPath.class);
        Map<String, String> map = new HashMap<>();
//        遍历节点
        for (Element element : elementsAnnotateWith) {
            TypeElement typeElement = (TypeElement) element;
//            从节点获取注解
            BindPath annotation = typeElement.getAnnotation(BindPath.class);
//            获取注解内容
            String key = annotation.value();
//            获取节点全类名
            Name activityName = typeElement.getQualifiedName();
//            将key-value存入map
            map.put(key, activityName + ".class");
        }
        if (map.size()>0){
            Writer writer=null;
            String activityName="ActivityUtil"+System.currentTimeMillis();
            try {
//                创建java文件
                JavaFileObject sourceFile = filer.createSourceFile("com.syw.util." + activityName);
                writer=sourceFile.openWriter();
//                拼接stringbuffer
                StringBuffer stringBuffer=new StringBuffer();
                stringBuffer.append("package com.syw.util;\n");
                stringBuffer.append("import com.syw.aroutelibrary.Aroute;\n");
                stringBuffer.append("import com.syw.aroutelibrary.IRouter;\n");
                stringBuffer.append("public class "+activityName+" implements IRouter{\n"
                +"@Override\n"+
                        "public void putActivity(){\n");

                Iterator<String> iterator = map.keySet().iterator();
                while (iterator.hasNext()){
                    String key=iterator.next();
                    String className=map.get(key);
                    stringBuffer.append("Aroute.getInstance().addActivity(\""+key+"\","+className
                    +");\n");
                }
                stringBuffer.append("\n}\n}");
//                写入java文件
                writer.write(stringBuffer.toString());
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (writer!=null){
                    try {
                        writer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return false;
    }
}

各个模块添加注解依赖

//    编译时模块
    implementation project(':annotation')
//    编译到这行代码时,
//    1.向javac注册我们这个自定义的注解处理器
//    2.生成META-INF/services/javax.annotation.processing.Processor文件
//    3.通过反射执行生成文件的方法
    annotationProcessor project(':annotation_compiler')

AutoService生成文件如下图所示
在这里插入图片描述
自定义注解处理器最终生成的代码如下图所示
在这里插入图片描述

所有生成的部分已经完成,现在需要执行生成的代码,将所有内容存到map中也就是执行Aroute的init()方法

我在主项目的mainactivity中执行了该方法,如下所示

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Aroute.getInstance().init(this);
    }

    public void tologin(View view) {
        Aroute.getInstance().jumpActivity("login/login",null);
    }
}

完成跳转

总结:1.创建一个JavaLibrary用于注解,自定义我们的注解
2.创建一个JavaLibiary用于注解处理器,功能是:遍历dex文件中的类,将包含我们制定注解的对象添加到map,然后写入指定路径的java文件
3.各个模块依赖注解和注解处理器,当编译到annotationProcessor时,向javac注册注解处理器,生成Processor文件,通过反射方法执行注解处理器生成代码的方法
4.通过Aroute.init()方法,获取所有的生成代码,然后执行,实现将所有方法添加到map。当需要跳转的时候,直接根据key获取到对应的activity,完成跳转
ARoute源码解读之自动生成路由映射文件 在开始ARoute源码分析之前需要先了解Javapoet和APT分别是什么? JavaPoet 官方链接:https://github.com/square/javapoet A Java API for generating .java source files. Source file generation can be useful when doing things such as annotation processing or interacting with metadata files (e 阅读详情

相关推荐

Android路由ARoute使用

1、不能在kotlin module中添加ARoute的java引入和配置,同理反过来java module中添加ARoute的kotlin引入和配置也不行,虽然运行不会报错,但是会提示找不到路劲。3、如果提示"there's no route matched path",要反复检查引用和配置,仅仅这几步,其他没有额外设置的了,错了一步,就会跳转不成功。,"/app/MainActivity"是自定义的路劲,注意的是此路劲至少需要有两级/xxx/xxx,2.跳转到上述页面方法。,这里就不一 一介绍了。

wangqing830414的专栏 751

android学习笔记(二):ARoute(阿里路由)

跨模块跳转框架之阿里路由的简单入门

qq_43270141的博客 2102

Aroute 功能的使用

Aroute 多模块跳转 子模块跳转到主模块 拦截弹框 拦截跳转

【Android 组件化】使用 ARoute 实现组件化 ( 完整组件化项目框架 )

一、ARoute 引入、 1、配置 build.gradle、 二、3 个模块的界面跳转、 三、组件化配置、 1、全局配置、 2、工程下的 build.gradle 配置、 3、app 模块下的 build.gradle 配置、 四、Module 模块的组件化配置、 1、创建组件模式下使用的类和清单文件、 2、动态切换 集成模式 / 组件模式、 五、博客资源、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 3976

从零配置EtherCAT IGH主站:手把手教你处理内核版本与实时性优化的那些坑

本文详细指导如何从零配置EtherCAT IGH主站,涵盖内核版本适配、实时性优化及常见问题解决方案。通过精确匹配内核头文件、应用实时补丁和优化网卡驱动,帮助开发者实现微秒级响应,适用于工业自动化、机器人控制等高精度场景。

weixin_30790841的博客 382

ESD 防护深度解析:模型、等级、系统设计与防护策略

本文系统阐述了静电放电(ESD)防护的核心技术体系。首先对比分析了HBM(人体模型)和CDM(充电设备模型)两种基础ESD模型的物理特性、测试标准及分级要求,指出相同电压下CDM的破坏性是HBM的15-20倍。其次详细解析了IEC61000-4-2系统级ESD标准,包括接触/空气放电测试方法及判定等级。重点提出了系统级防护的三层架构:空间隔离(≥10mm间距)、电气隔离(地平面分割)和TVS管选型(响应时间<1ns),并对比了MOV、SCR等防护器件特性。针对不同应用场景(消费电子、工业控制等)给出了差异化

bother3000的博客 1882

Kotlin AndroidX ARoute Hilt 组件化开发示例

项目介绍 该项目只是简单的组件化开发的示例,搭建了组件化开发的雏形。 暂时没有实现内容的开发工作,目前实现功能有: 网络模块的封装、ARoute的使用方法、登陆功能的实现(UI未实现)。 使用了Kotlin + AndroidX + 协程 + Retrofit + ViewModel + ARouter 项目地址 Route 组件化开发示例 https://github.com/xiaoerMr/Route 组件划分 App 模块 moduel_basis 基础模块 moduel_login 登陆模

Mr.小二 1640

MQTT(轻量级消息中间件)基本使用指南

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是一种轻量级的发布 / 订阅模式(Pub/Sub)消息传输协议,专为低带宽、不稳定网络环境设计,广泛应用于物联网(IoT)、移动设备、传感器网络等场景(如空气净化器、智能家居设备的远程控制)。Eclipse Mosquitto 是一款轻量级、开源的 MQTT 消息服务器(Broker),由 Eclipse 基金会维护,专为低资源消耗和易用性设计。

墨鸦的博客 1万+

从零开始组件化(2)_路由跳转方式和手动搭建组件化路由

在上一篇文章组件化-从零开始组件化(1)_z936689039的博客-优快云博客中,我们已经搭建好整体框架了,然后问题就来了,因为组件化,各个业务组件是互相不依赖的,那假如涉及到跳转,我们应该怎么做呢,目前这块的做法有2种 1.隐式跳转 通过AndroidManifest中对要跳转的activity设置action值,然后跳转的时候,指定对应的action,从而实现跳转的,例如 在要隐式跳转的activity中配置: //清单文件注册 <activity android:name=".Ma

z936689039的博客 4423

〖Python接口自动化测试实战篇④〗- 接口自动化测试详解

[接口测试] 是相对来说和我们的功能测试 [最为接近的一种自动化测试手段] ,所以我们首先来学习接口测试的内容。 实现接口的开发与接口的测试,在我们的思维上、想法上、面向的态度上都是不一样的。所以大家要有一个思维上的转换,要认识了解一下 接口测试到底是做什么的、它的功能、意义在哪里。...

易编橙 · 终身成长社群,相遇已是上上签! 5万+

GRCNN抓取网络学习3【自制Jacquard数据集模型调优】

请先完成,这样有利于下面操作的理解!然后第二步是,有了自己的数据集输入到GRCNN中是三种文件,那么可以GRCNN抓取网络学习2【自制Jacquard数据集训练】!既然学会训练,那么开展下一步计划模型调优。GRCNN源码:https://github.com/skumra/robotic-grasping。

vor234的博客 2499

组件化1---组件化架构初步原理

完整组化件和插件化可以参考我的github项目,已经用在线上项目中 组件化: 就是将一个完整的功能拆分成多个子模块,而每个子模块可以独立编译和运行,也可以任意的组合成一个新的APP 优势: 团队开发过程中方便项目管理,它分工非常明确互不干扰,不存在甩锅. 组件与组件之间他们不相互依赖却可以相互交互,任意组合,高度解耦. 可以分模块打包,分模块测试,可以统一版本的管理(比如buildto...

qq_35651451的博客 744

基于SOLIDWORKS API的工业级插件开发指南

SOLIDWORKS API是基于COM技术的一套开发接口,支持C#、VB.NET等语言,用于自动化建模、属性管理、界面定制等功能。

举世誉之而不加劝,举世非之而不加沮,定乎内外之分,辩乎荣辱之境,斯已矣。 2744

架构师学习--组件化开发之路由ARouter设计

使用过阿里开源项目ARouter路由框架的都知道,为组件化开发打开了一扇大门。使用组件化的目的就是解决团队开发,各自负责各自的模块,互不干扰,模块之间能够完全解耦,加快开发效率。这样做还有一个好处就是,如果有一个功能模块不需要了,可以在app中删除该模块的依赖即可,不需要大量的删除代码。核心技术是Javapoet,没有了解它的可以看另外一篇文章javapoet简单实用 一、如何实现模块之间acti...

qinbin2015的博客 392

2026年运维工程师常见面试选择题

这篇文章总结了30道Linux运维面试常见问题及解析,涵盖基础命令、系统监控、故障排查、数据库、缓存、容器编排等多个方面。主要内容包括: 基础命令使用:如df查看磁盘、free查看内存、top监控进程等 系统监控与故障排查:负载判断、端口检查、进程管理等 中间件相关:Nginx状态码、MySQL主从复制、Redis缓存问题 容器技术:Docker优势、Kubernetes作用 运维理念:高可用、监控告警、发布策略、备份容灾 工作原则:故障处理优先级、运维工程师核心能力 文章不仅提供标准答案,还解析了各命令的

不务正业的猿 193

一文让你轻松理解Wi-Fi理论速率计算方式

如上所示,在使用FDM的802.11协议上,最小子载波带宽为312.5KHz,那一个信道频宽为20MHz的信道可以分成64个子载波,但是由于技术原因,有效使用的是52个子载波,实际用于数据传输的只有48个,有4个子载波充当导频载波。载波:交流信号或者直流信号本身不具备数据传输能力,但是如果信号发生很小的波动或者变化,从而实现数据的收发。所谓子载波,就是将信号划为为很多的小信道,这些小信道可以实现数据的并发传输,子载波我们英文称为subcarrier,也称为音调(tone)。Symbol time如下所示。

1042484520@qq.com(邮箱) 3447

我的Compose开源项目《出行防疫App》已发布

在我的新书《Android Jetpack开发:原理解析与应用实战》项目实战中,我们实现了一个MVVM版本的出行防疫App。之前说过,会开发对应的Compose版本,如今,他来了~如果你还没看过非Compose版本可以点击链接查看。这是一款MVVM模式的Compose App,采用了组件化、Aroute、协程、flow等技术,适合初学者学习使用。此项目将长期维护,后续所有的新技术、平台适配等都将基于此项目实践。

黄林晴 1986

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

基于ARouter的Android组件化实现

网上组件化的文章很多,但大多数文章都从底层的细枝末节开始讲述,由下而上给人一种这门技术“博大精深”望而生畏的感觉。而我写这篇文章的初衷就是由上而下,希望别人在阅读的过程中能够觉得“组件化原来也就是这几个东西”的感觉。 首先我们来看一下组件化项目和传统项目的区别 在传统的项目里 我们通常情况下会有一个core的libary模块和一个app的application模块,业务中的逻辑都写在app中各个功...

weixin_34261415的博客 174

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

2024年最全双叒叕-一个-Android-MVVM-组件化架构框架?,2024年最新带你全面掌握高级知识点的软件

文章会持续更新的。绝对干货!!!Android进阶学习全套手册关于实战,我想每一个做开发的都有话要说,对于小白而言,缺乏实战经验是通病,那么除了在实际工作过程当中,我们如何去更了解实战方面的内容呢?实际上,我们很有必要去看一些实战相关的电子书。

2401_84561461的博客 948

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

改造Arouter的模块调用,创建更适用于组件化开发的路由框架

  作者catRuan ,转载请注明出处       Arouter是阿里开发的一款用于模块间跳转、通讯的路由工具 Arouter源码       关于Arouter的实现原理,请参照作者另外一篇博客 Arouter源码解读       公司在进行组件化开发时有幸选用了Arouter作为模块管理工具,在使用过程中发现其并非能够彻底解决跨模块调用时的耦合的问题      例如,当我想在当前...

u011791526的博客 1839

记一次高级android面试经历

1.单例模式的优缺点 2.retrofit源码分析 优缺点 retrofit注解是通过什么实现的 3. rxjava源码分析,优缺点 rxjava如何进行线程切换 4.mvp和mvc,mvvm的原理解释,以及优缺点比较 5.sp是安全的吗 6.进程间通信 7.怎么写安全的广播broadcast和服务service 8.aroute源码解析 router拦截功能 9.热修复原理 10.组件化,插件化...

白龙的博客 862

ARouter路由实现原理(手写核心原理,实现通信一目了然)

组件化通信,跳转有两种实现方案: 核心:编译时生成文件,运行时执行文件 第一种方案: 使用Intent 隐士跳转方式。 /** *隐士跳转首页 清空现有栈,创建新栈 */ public static void newTaskMainActivity(Activity activity){ Intent intent = new Intent(); ...

weixin_39079048的博客 756

Android组件化之ARouter的使用,安卓学习路线图

} 应用内跳转 使用 ARouter 进行应用内跳转非常简单,只需要在要跳转的 Activity 上添加 @Route 注解即可,具体如下: // 配置的path至少需要两级,如/xx/xxx @Route(path = FirstActivity.PATH) public class FirstActivity extends AppCompatActivity { public static final String PATH = “/test/firstActivity”; @Override pr

m0_66264533的博客 313

Arouter的实现原理?

组件化的各个业务模块module之间,相互独立,没有依赖关系,所以,在一个module中,不能获取另外一个module中的Activity.class。这段Java代码的功能,就是把activity.class存入HashMap中,需要跳转到其他Module的Activity时,直接从HashMap里面取出activity.class。3.通过APT技术,根据保存的类名和包名,生成对应的Java代码,这段Java代码的功能就是把activity.class存入路由表,也就是HashMap。

2301_76766616的博客 614

组件化框架设计之阿里巴巴开源路由框架——ARouter原理分析(一)

阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 背景 当项目的业务越来越复杂,业务线越来越多的时候,就需要按照业务线去分不同的模块去开发,这样专门的人负责专门的业务模块,最终上线由壳工程去负责进行组合打包各个module,完成业务的快速迭代。整个过程会涉及到各个模块间进行通信,比如订单模块和个人...

AndroidAlvin的博客 356

Android高级进阶系列:注解处理器APT用法详解

这段时间在写一些组件化相关的文章,其中有用到开源库ARoute相关知识,查看了下源码,内部使用了APT动态生成类的方式,于是就有了这篇文章,记录下自己对APT注解处理器的一些理解。

m0_70749039的博客 711
上一篇: 微信小程序常用功能所需条件整理
下一篇: 20201124java基础知识整理
ForMuHan
博客等级 码龄10年 6粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值