组件化(一)

早期的单一分层模式 问题一:无论分包怎么做,随着项目增大,项目失去层次感,后面接手的人扑街 问
题二:包名约束太弱,稍有不注意,就会不同业务包直接互相调用,代码高耦合 问题三:多人开发在版
本管理中,容易出现代码覆盖冲突等问题

所有的代码都写在app模块中不同的包里面

1.什么是组件化,为什么需要组件化

组件化的意义:不相互依赖,可以相互交互,任意组合,高度解耦,自由拆卸,自由组装,重复利用,
分层独立化

此时:app不在是老大,子模块都是小弟
组件化后,所有的module都平起平坐,有人说app的module在组件化中是个壳子,这也是为什么成为
app壳工程的原因
同学们思考,如果没有组件化,还是单一: 1.彻底砍掉order子模块,需要多少工作? 2.如何给项目增
加一个子模块(钱包)? ........

2.集成环境/组件环境自动部署配置 2.1:Gradle中的基本流程需要简单知道,后续我们会专门讲 2.2:
Gradle中的Groovy其实属于糖果语法,就是弱类型语法,我们来测试下 2.3:我们在项目的开发过程
中,一定要去优化我们的gradle文件,例如:把公用的内容抽取 2.4:项目的开发过程中,关于一切与
“正式环境”,“测试环境” 相关的应该用Gradle进行配置

Phone Module和Android Library区别、切换:

组件化开发规范: order order前缀(src类 和 res资源) personal personal前缀( src类 和 res资源)
app 可不改,让它默认 ……
组件化开发的临时代码,集成化打包时动态隔离

// 配置资源路径,方便测试环境,打包不集成到正式环境
sourceSets {
main {
if (!isRelease) {
// 如果是组件化模式,需要单独运行时
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
// 集成化模式,整个项目打包apk
manifest.srcFile 'src/main/AndroidManifest.xml'
java {
// release 时 debug 目录下文件不需要合并到主工程
exclude '**/debug/**'
}
}
}
}
注意事项:
src/main/debug/AndroidManifest.xml
子模块包名/debug/测试代码.java

源码环节: app build.gradle:

apply plugin: 'com.android.application'
println("Derry ---> app Student hao 1")
println "Derry ---> app Student hao 2"
// 完整的方式
def androidID = rootProject.ext.androidID
android {
 compileSdkVersion androidID.compileSdkVersion
 buildToolsVersion androidID.buildToolsVersion
 defaultConfig {
   applicationId appID.app
   minSdkVersion androidID.minSdkVersion
   targetSdkVersion androidID.targetSdkVersion
   versionCode androidID.versionCode
   versionName androidID.versionName
   testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
   // 给Java代码暴漏,标记,正式环境 和 测试环境 的标记
   // 组件化 和 集成化 的时候需要
   buildConfigField("boolean", "isRelease", String.valueOf(isRelease))
 }
 buildTypes {
   debug {
     buildConfigField("String", "debug", "\"${url.debug}\"")
   }
   release {
     buildConfigField("String", "release", "\"${url.release}\"")
     minifyEnabled false
     proguardFiles getDefaultProguardFile('proguard-android-
optimize.txt'), 'proguard-rules.pro'
   }
 }
}
dependencies {
 implementation fileTree(dir: "libs", include: ["*.jar"])
 // 300行
 /*implementation "androidx.appcompat:appcompat:1.2.0"
 implementation "androidx.constraintlayout:constraintlayout:2.0.1"
 implementation "com.google.android.material:material:1.1.0"
 implementation "androidx.vectordrawable:vectordrawable:1.1.0"
 implementation "androidx.navigation:navigation-fragment:2.2.2"
 implementation "androidx.navigation:navigation-ui:2.2.2"
 implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"*/
 // 一行搞定 300 行
 dependenciesID.each { k, v -> implementation v }
testImplementation 'junit:junit:4.12'
 androidTestImplementation 'androidx.test.ext:junit:1.1.2'
 androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
 // 如果是集成化模式,做发布版本时。各个模块都不能独立运行了
 if (isRelease) {
   // 依附App壳
   implementation project(':login')
   implementation project(':register')
 } else {
   // 不需要做事情,组件环境,不需要依附App壳
 }
}

library build.gradle:

apply plugin: 'com.android.library'
println "Derry ---> lib Student hao 2"
// 完整的方式
def androidID = rootProject.ext.androidID
android {
 compileSdkVersion androidID.compileSdkVersion
 buildToolsVersion androidID.buildToolsVersion
 defaultConfig {
   minSdkVersion androidID.minSdkVersion
   targetSdkVersion androidID.targetSdkVersion
   versionCode androidID.versionCode
   versionName androidID.versionName
   testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
   consumerProguardFiles "consumer-rules.pro"
 }
 buildTypes {
   release {
     minifyEnabled false
     proguardFiles getDefaultProguardFile('proguard-android-
optimize.txt'), 'proguard-rules.pro'
   }
 }
}
dependencies {
 implementation fileTree(dir: "libs", include: ["*.jar"])
 // 300 行
 /*implementation "androidx.appcompat:appcompat:1.2.0"
 implementation "androidx.constraintlayout:constraintlayout:2.0.1"
 implementation "com.google.android.material:material:1.1.0"
 implementation "androidx.vectordrawable:vectordrawable:1.1.0"
 implementation "androidx.navigation:navigation-fragment:2.2.2"
 implementation "androidx.navigation:navigation-ui:2.2.2"
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"*/
 // 一行搞定 300 行
 dependenciesID.each { k, v -> implementation v }
 testImplementation 'junit:junit:4.12'
 androidTestImplementation 'androidx.test.ext:junit:1.1.2'
 androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

project build.gradle:

// 根目录下的build.gradle 引入
apply from : 'derry.gradle'

test.gradle 公共一份gradle:

// 糖果语法
// 扩展快
ext {
 // 正式环境 和 测试环境
 isRelease = true
 // 正式环境 和 测试环境 URL 配置
 url = [
     "debug" : "https://192.188.22.99/debug",
     "release": "https://192.188.22.99/release"
 ]
 // 建立Map存储, key 和 value 都是自定义的
 androidID = [
     compileSdkVersion: 30,
     buildToolsVersion: "30.0.1",
     applicationId  : "com.derry.derry",
     minSdkVersion  : 16,
     targetSdkVersion : 30,
     versionCode   : 1,
     versionName   : "1.0",
 ]
 // 建立Map存储, key 和 value 都是自定义的
 appID = [
     app: "com.derry.derry",
     login: "com.derry.login",
     register: "com.derry.register"
 ]
 // 300
 // 300 行 MAP key value
 dependenciesID = [
     "appcompat"    : "androidx.appcompat:appcompat:1.2.0",
     "constraintlayout":
"androidx.constraintlayout:constraintlayout:2.0.1",
     "material"    : "com.google.android.material:material:1.1.0",
     "vectordrawable" : "androidx.vectordrawable:vectordrawable:1.1.0",
     "fragment"    : "androidx.navigation:navigation-fragment:2.2.2",
     "ui"       : "androidx.navigation:navigation-ui:2.2.2",
     "extensions"   : "androidx.lifecycle:lifecycle-extensions:2.2.0",
 ]
}

app Java代码区域:

public class NetworkConfig {
 // 测试 服务器 地址
 public static final String DEBUG = "https://192.188.22.99/debug";
 // 正式 服务器 地址
 public static final String RELEAE = "https://192.188.22.99/release";
}

布局:

<TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="进入Login模块"
   app:layout_constraintBottom_toBottomOf="parent"
   app:layout_constraintLeft_toLeftOf="parent"
   app:layout_constraintRight_toRightOf="parent"
   app:layout_constraintTop_toTopOf="parent"
   android:onClick="startLoginModel"
   />

组件化中 子模块交互方式(非ARouter版)

3.1:方式一 使用 EventBus的方式,缺点是:EventBean维护成本太高,不好去管理: 3.2:方式二 使
用广播的方式,缺点是:不好管理,都统一发出去了 3.3:方式三 使用隐士意图方式,缺点是:在
AndroidManifest.xml里面配置xml写的太多了 3.4:方式四 使用类加载方式,缺点就是,容易写错包名
类名,缺点较少(尝试写写这种方式) 3.5:方式五 使用全局Map的方式,缺点是,要注册很多的对象

 

方式一:类加载技术交互

方式二:全局Map记录信息的方式交互:

组件化二的学习目录: 1.APT技术。 2.高级用法JavaPoet。 3.组件化项目部署,ARouter原理。
APT是什么? APT(Annotation Processing Tool) 是一种处理注释的工具,它对源代码文件进行检测找出
其中的Annotation,根据注解自动生成代码,如果想要自定义的注解处理器能够正常运行,必须要通过
APT工具来进行处理。 也可以这样理解,只有通过声明APT工具后,程序在编译期间自定义注解解释器
才能执行。 通俗理解:根据规则,帮我们生成代码、生成类文件
APT中用到的结构体思路

element组成的结构体
<html>
<body>
 <div>.....</ div >
</ body >
</ html >
对于java源文件来说,它同样也是一种结构体语言
package com.netease.apt; // PackageElement 包元素/节点
public class Main{      // TypeElement 类元素/节点
     private int x; // VariableElement 属性元素/节点
     private Main(){ // ExecuteableElement 方法元素/节点
     }
     private void print(String msg){}
}

APT中用到的重要元素

PackageElement
表示一个包程序元素。提供对有关包及其成员的信息的访问
ExecutableElement
表示某个类或接口的方法、构造方法或初始化程序(静态或实例)
TypeElement
表示一个类或接口程序元素。提供对有关类型及其成员的信息的访问
VariableElement
表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数

APT中用到API

getEnclosedElements() 返回该元素直接包含的子元素
getEnclosingElement() 返回包含该element的父element,与上一个方法相反
getKind()      返回element的类型,判断是哪种element
getModifiers()    获取修饰关键字,入public static final等关键字
getSimpleName()    获取名字,不带包名
getQualifiedName()  获取全名,如果是类的话,包含完整的包名路径
getParameters()    获取方法的参数元素,每个元素是一个VariableElement
getReturnType()    获取方法元素的返回值
getConstantValue()  如果属性变量被final修饰,则可以使用该方法获取它的值

1.APT技术 APT全称: annotation process tool是一种处理注释的工具,它对源代码文件进行检测找出其
中的Annotation,使用Annotation进行额外的处理。
APT 编译的时候 ----------> 处理注解 --------> 生成代码----------> 编译完成
APT 传统方式 ---------------> 生成 java文件
APT JavaPoet方式 ---------> 生成Java文件
传统方式 那些 开源项目有用到?
答:看看EventBus源码就知道了 传统方式:优点(编程的流程写下去) 缺点(没有oop思想加入进
来) https://github.com/greenrobot/EventBus
as 4.0.1 输出:https://blog.csdn.net/u011418943/article/details/106876898

JavaPoet是什么? JavaPoet是square推出的开源java代码生成框架,提供Java Api生成.java源文件 这个
框架功能非常实用,也是我们习惯的Java面向对象OOP语法 可以很方便的使用它根据注解生成对应代码
通过这种自动化生成代码的方式, 可以让我们用更加简洁优雅的方式要替代繁琐冗杂的重复工作
项目主页及源码:https://github.com/square/javapoet
JavaPoet相关

类对象               说明
MethodSpec     代表一个构造函数或方法声明
TypeSpec     代表一个类,接口,或者枚举声明
FieldSpec     代表一个成员变量,一个字段声明
JavaFile     包含一个顶级类的Java文件
ParameterSpec   用来创建参数
AnnotationSpec   用来创建注解
ClassName     用来包装一个类
TypeName     类型,如在添加返回值类型是使用 TypeName.VOID
$S 字符串,如:$S, ”hello”
$T 类、接口,如:$T, MainActivity

2.高级用法JavaPoet
JavaPoet到底是什么? 答:oop思想方式:优点(加入oop思想) 缺点(不习惯,倒序)

JavaPoet真的比传统方式好吗?
答:并不是这样的,如果复杂的代码生成,反而效率低下 发展趋势,oop思想,真正的掌握JavaPoet,
爱不释手
https://github.com/alibaba/ARouter https://github.com/JakeWharton/butterknife
APT的学习,创建JavaLib,要监控到,编译期

// 构建 -------》 【编译时期.....】 ------》打包 ----》安装
 // AS3.4.1 + Gradle 5.1.1 + auto-service:1.0-rc4
 compileOnly'com.google.auto.service:auto-service:1.0-rc4'
 annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'

组件化项目部署,ARouter原理

3.1:整体的项目结构介绍(后续组件化中,一直用这个工程了,不再创建新的了) 3.2:路由表学习

RouterBean对象角色: Element类节点为什么也要存起来? 因为将来我们要在注解处理器中,循环拿
到每个类节点。方便赋值和调用 Element它是javax.lang包下的,不属于Android Library

public enum Type {
ACTIVITY
}
// 枚举类型:Activity
private Type type;
// 类节点
private Element element;
// 注解使用的类对象
private Class<?> clazz;
// 路由地址
private String path;
// 路由组
private String group;

ARouterLoadGroup接口 Map<String, Class<? extends ARouterLoadPath>> 需要生成路由路径文件
后,才能生成路由组文件 接口方式容易拓展、通用

/**
* 路由组Group加载数据接口
*/
public interface ARouterLoadGroup {
 /**
  * 加载路由组Group数据
  * 比如:"app", ARouter$$Path$$app.class(实现了ARouterLoadPath接口)
  *
  * @return key:"app", value:"app"分组对应的路由详细对象类
  */
 Map<String, Class<? extends ARouterLoadPath>> loadGroup();
}

ARouterLoadPath接口: Map<String, RouterBean> OOP思想,让单纯的targetClass变成更灵活的
RouterBean对象 接口方式容易拓展、通用

/**
* 路由组Group对应的详细Path加载数据接口
* 比如:app分组对应有哪些类需要加载
*/
public interface ARouterLoadPath {
 /**
  * 加载路由组Group中的Path详细数据
  * 比如:"app"分组下有这些信息:
  *
  * @return key:"/app/MainActivity", value:MainActivity信息封装到RouterBean对象
中
  */
 Map<String, RouterBean> loadPath();
}

 

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值