博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
组件化下EventBus的消息类型自动编译
阅读量:7089 次
发布时间:2019-06-28

本文共 7710 字,大约阅读时间需要 25 分钟。

今天这个题目很难取,组件化范畴的内容,又是EventBus的相关内容,但是通过gradle插件化的形式来做,简单就说成组件化下EventBus的消息类型自动编译,有更好主意的小伙伴可以推荐。先说下背景,组件化过程中肯定涉及到数据的传递问题,这个库是比较流行的方式,用过EventBus的小伙伴都知道需要先定义一个消息类型。在组件化工程里面一般都会把消息类型定义到公共模块,这样跨组件才能传递。这样做能实现目的,但是有两个弊端:

  • 需要手动去更改公共库,这就给公共库带来一定的风险,越来越多的代码往公共库中添加会造成后期很难维护,组件化的边界难于界定,公共库需要保持稳定
  • 各组件之间的拆分也不是很干净,如果修改组件通信内容的同时需要修改公共库中的内容,如果组件模块A的开发看不到公共库中源码呢?就捉瞎了

所以我们的目的是,组件需要接受或者发送的消息类型直接在自己组件范围内定义,不需要去修改组件外的任何代码,修改越少,bug就越少,就能越早下班不是吗?

1.结果

先看下整个项目结构

分成app/event/modulea/moduleb四个部分 其中app中发送消息,a和b可以接收到,a和b中的内容大同小异,就只看下a中的代码,一个
ADisplay用于显示接收到的消息,一个
ModuleaMsg用于定义消息类型。

看下 ADisplay中的代码,要接受的是ModuleaMsg消息:

@Subscribe(threadMode = ThreadMode.MAIN)public void onMessageEvent(ModuleaMsg msg) {      System.out.println("Module A received msg = " + msg.msg);      EventBus.getDefault().unregister(this);}复制代码

ModuleaMsg就是消息类型?在a组件中登记,写一个以.event结尾的文件,在里面写入代码就可

这样就完成了组件需要完成的全部工作了,完全不需要修改其他的组件。

在发送的地方,我们这里直接在app组件中发送消息,

ModuleaMsg moduleaMsg = new ModuleaMsg();        moduleaMsg.msg = "send from app";        EventBus.getDefault().post(moduleaMsg);        ModulebMsg modulebMsg = new ModulebMsg();        modulebMsg.num = 10086;        EventBus.getDefault().post(modulebMsg);复制代码

modulea和moduleb接收到消息:

Module A received msg = send from appModule B received msg = 10086复制代码

上面就是全部的使用方式了,如果还有兴趣的小伙伴接着往下看实现原理了。

2.实现方式

其实就是通过gradle插件的方式实现,需要了解怎么定义gradle插件的可以参考我之前的,这里就不再赘述,我们直接看下插件里面的代码, 主要任务都在project.afterEvaluate中完成,

project.afterEvaluate {            def eventModule = project.rootProject.childProjects.get(project.EventPluginExt.eventModuleName)            if (eventModule == project) {                throw new GradleException('event module should not be itself!')            }            if (eventModule == null || !eventModule.projectDir.exists()) {                throw new GradleException('event module is not exists')            }            def cleanEventTask = project.task("eventClean", type: Delete) {                delete("${project.rootProject.projectDir}/${eventModule.name}/src/main/java")            }            project.tasks.getByName("clean").dependsOn cleanEventTask            ...}复制代码

首先判断工程中是否有project.EventPluginExt.eventModuleName (= event)这个模块,在第一张图中可以看到有个event这个模块,里面包含了所有的消息类型

然后定义一个清除组件下旧的.event后缀的文件,优先于gradle cleantask。

接着往下看,接着会拿到所有构件体,分成两种,lib模块或者application模块

getVariants().all { variant ->                def variantName = Utils.captureName(variant.name)                System.out.println("variantName is " + variantName)                if (isLibrary()) {                } else {                }}    private boolean isLibrary() {        return project.android.hasProperty('libraryVariants')    }复制代码

先看下lib模块下面的代码,分成三部分,先看下第一部分:

def intoAssetdef assetDir = Utils.getOneAssetDir(variant)if (assetDir == null) {     intoAsset = "${project.projectDir}/src/main/assets/$eventFolder"} else {     intoAsset = assetDir.absolutePath + "/$eventFolder"}def intoEventSdk = "${project.rootProject.projectDir}/${eventModule.name}/src/main/java"List list = new ArrayList()variant.sourceSets.each { sourceSet ->sourceSet.java.srcDirs.each { file ->list.add(file)}}def javaSrcList = list as String[]复制代码

首先拿到lib里面的assets目录,是为了后面把所有lib中的.event文件都保存到apk中的assets目录中的eventFolder文件夹;然后定义根目录下event组件下的文件位置,最后拿到lib下的所有代码文件。

接着看下第二部分,主要是定义任务task:

  1. eventLibCopyTask是拷贝任务,把前面拿到的javaSrcList.event后缀的文件复制到event模块下,并且修改后缀名为.java, 在执行preBuild前生成
  2. 拿到build过程的第一个task---preBuild
  3. 定义拷贝任务eventAssetsCopyTask,负责负责src/javasrc//.event->assets/cocoFolder//.event
  4. 获取generateAssets任务
  5. 获取mergeAssets任务
  6. 获取当前variant编译任务——如assembleDebug/assembleRease
  7. 定义删除任务-删除的是lib下assets中的delete assets/cocoFolder//.event文件
Task eventLibCopyTask = project.task("eventLibCopyTaskFor" + variantName, type: Copy) {                        includeEmptyDirs = false                        from javaSrcList                        into intoEventSdk                        include "**/*.${project.EventPluginExt.postFix}"                        rename "(.*)${project.EventPluginExt.postFix}", '$1java'}Task preBuildTask = project.tasks.getByName("pre" + variantName + "Build")Task eventAssetsCopyTask = project.task("eventAssetsCopyTaskFor" + variantName, type: Copy) {                        includeEmptyDirs = false                        from javaSrcList                        into intoAsset                        include "**/*.${project.EventPluginExt.postFix}"}Task generateAssetsTask = project.tasks.getByName("generate" + variantName + "Assets")Task mergeAssetsTask = variant.mergeAssetsTask assembleTask = variant.assembleTask eventAssetsDeleteTask = project.task("eventAssetsDeleteFor" + variantName, type: Delete) {                        delete intoAsset}复制代码

第三部分就是定义上面几个任务的执行顺序,第一步肯定是要拷贝.event文件到event模块下面,几个任务顺序:

1) 拷贝lib中event到event中2) preBuild3) 拷贝lib中event到assets中4) generateAssets5) mergeAssets6) 删除assets中的event文件7) assemble复制代码
preBuildTask.dependsOn eventLibCopyTaskgenerateAssetsTask.dependsOn eventAssetsCopyTaskmergeAssetsTask.finalizedBy eventAssetsDeleteTaskassembleTask.finalizedBy eventAssetsDeleteTask// 添加event的预编译依赖,避免event模块在编译完成之后再执行当前project的event拷贝任务,导致类查找不到的问题def preEventBuildTask = nulltry{       preEventBuildTask = eventModule.tasks.getByName("preBuild")} catch (Exception ignored) {}if(preEventBuildTask != null) {       preEventBuildTask.mustRunAfter eventLibCopyTask}复制代码

上面就是lib模块的代码逻辑,接下来看下application模块的相关逻辑,application模块会有依赖的aar,aar里面可能有.event的文件,所以需要从依赖中循环拿到这些文件拷贝到event模块中

分成两个步骤,先看下第一个步骤,就是从aar依赖中把.event后缀的文件移动到项目目录的event 模块中

Task appUnpackTask = nullif (variant.hasProperty("compileConfiguration")) {       // For Android Gradle plugin >= 2.5      Attribute artifactType = Attribute.of("artifactType", String)     FileCollection classPathConfig = variant.compileConfiguration.incoming.artifactView {             attributes {                 it.attribute(artifactType, "aar")             }}.filesSystem.out.println("classPathConfig = " + classPathConfig)appUnpackTask = project.task("eventAppUnpack" + variantName, type: Copy) {          includeEmptyDirs = false          classPathConfig.each {                from(project.zipTree(it))          }          into "${project.rootProject.projectDir}/${eventModule.name}/src/main/java"          include "**/$eventFolder/**/*.${project.EventPluginExt.postFix}"          rename "(.*)${project.EventPluginExt.postFix}", '$1java'          eachFile {                it.path = it.path.replaceFirst(".*$eventFolder", '')          }}} 复制代码

第二个步骤就是把app模块下的后缀文件拷贝到event 模块中,逻辑和前面lib模块的逻辑一样的,实现效果就是javasrc/*.event->event/src/javasrc/*/*.java就不重复介绍了

List list = new ArrayList()variant.sourceSets.each { sourceSet ->sourceSet.java.srcDirs.each { file ->           list.add(file) }}def javaSrcList = list as String[]System.out.println("javaSrcList is " + javaSrcList)def intoEventSdk = "${project.rootProject.projectDir}/${eventModule.name}/src/main/java"Task eventAppCopyTask = project.task("eventAppCopyTaskFor" + variantName, type: Copy) {                        includeEmptyDirs = false                        from javaSrcList                        into intoEventSdk                        include "**/*.${project.EventPluginExt.postFix}"                        rename "(.*)${project.EventPluginExt.postFix}", '$1java'}if (appUnpackTask != null) {     Task preBuildTask = project.tasks.getByName("pre" + variantName + "Build")     preBuildTask.dependsOn(appUnpackTask)     preBuildTask.dependsOn(eventAppCopyTask)     eventModule.tasks.getByName("preBuild").mustRunAfter appUnpackTask    eventModule.tasks.getByName("preBuild").mustRunAfter eventAppCopyTask}复制代码

3.总结

上面就是这个插件的全部内容了,主要就是完成消息类型的自动编译,可以辅助组件化更好的解耦,组件开发人员不需要去约定或者修改基础库才能达到数据传输的目的。有个需要注意的地方就是目前只支持模块是aar的包,jar包还不支持。

本文也是组件化的一部分内容,后面会再更新一些在大厂中用到的组件化知识,欢迎关注。

完。

转载于:https://juejin.im/post/5c7f66466fb9a04a0605a195

你可能感兴趣的文章
python中高阶函数与装饰器(3)
查看>>
ubuntu下pip的安装、升级和使用
查看>>
扩展easyui combobox实现年月选择下拉框
查看>>
c++设计模式之抽象工厂模式
查看>>
C/C++ exception类
查看>>
C#语言课程11月9日
查看>>
使用枚举实现单例
查看>>
【备忘录】毕业选课计划
查看>>
Python安装升级步骤
查看>>
使用k-近邻算法改进约会网站的配对效果
查看>>
c中static作用
查看>>
jdbc连接数据库
查看>>
excel控制
查看>>
Unicide编码
查看>>
Android入门(十一)SQLite CURD
查看>>
HDU 4978 A simple probability problem.(概率模型+凸包周长)
查看>>
memset struct含有string的崩溃
查看>>
时间范围比较
查看>>
给初学者的RxJava2.0教程(三)(转)
查看>>
探究ConcurrentHashMap中键值对在Segment[]的下标如何确定
查看>>