元件化一
簡介
單一分層問題: 1.随着項目增大,項目失去層次感,維護困難; 2.包名限制太弱,容易出現不同業務包直接互相調用,代碼高耦合; 3.多人開發在版 本管理中,容易出現代碼覆寫
(低内聚,高耦合,無重用,層次混亂)
**元件化的意義:**不互相依賴,可以互相互動,任意組合,高度解耦,自由拆卸,自由組裝,重複利用, 分層獨立化
具體實作: 業務子產品(order,login)互相獨立不會互相依賴,統一依賴底層子產品(base,common,net…),殼子產品(app)依賴各個業務子產品;
gradle簡單使用
抽取各個子產品公共變量:1.可以在項目級别的gradle檔案中進行定義。2,在項目級别再次定義一個gradle檔案,在項目的gradle檔案中通過apply from:‘my.gradle’
//my.gradle
ext{
isRelease = false
url = [ "debug" : "https://192.188.22.99/debug",
"release": "https://192.188.22.99/release" ]
androidID=[key:"value"]
appID=[key:"value"]
dependenciesID=[key:"value"]
}
//項目級别gradle
apply from:'my.gradle'//引入my.gradle
//app.gradle
def androidID=rootProject.ext.androidID//定義這個變量出于性能的考慮,可以不定義
//定義變量,可以在代碼中通過BuildConfig.isRelease使用
buildConfigField("boolean", "isRelease", String.valueOf(isRelease))
//login.gradle
if (isRelease) { // 如果是釋出版本時,各個子產品都不能獨立運作
apply plugin: 'com.android.library' // 正式環境 library不能獨立運作
} else {
apply plugin: 'com.android.application' // 測試環境 application獨立運作
}
if (!isRelease) { // 能夠獨立運作 必須要有appID
applicationId appID.login // 元件化模式能獨立運作才能有applicationId
}
sourceSets {
main {
if (!isRelease) {
// manifest.srcFile
manifest.srcFile 'src/main/debug/AndroidManifest.xml' // 生效
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
java {
// release 時 debug 目錄下檔案不需要合并到主工程
exclude "**/debug/**"
}
}
}
}
gradle檔案大體結構
android {
defaultConfig {}
buildTypes { release {} debug {}}
sourceSets { main { } }
}
dependencies {}
元件化 子子產品互動方式
一 使用 EventBus的方式,缺點是:EventBean維護成本太高,不好去管理:
二 使用廣播的方式,缺點是:不好管理,都統一發出去了
三 使用隐士意圖方式,缺點是:在AndroidManifest.xml裡面配置xml寫的太多了
四 使用類加載方式,缺點就是,容易寫錯包名類名,缺點較少(我們嘗試寫寫這種方式)
五 使用全局Map的方式,缺點是,要注冊很多的對象(我們嘗試寫寫這種方式)
//app-Application.java
// 如果項目有100個Activity,這種加法會不會太那個? 缺點
RecordPathManager.addGroupInfo("app", "MainActivity", MainActivity.class);
RecordPathManager.addGroupInfo("order", "Order_MainActivity", Order_MainActivity.class);
//order-OrderActivity.java
public void jumpPersonal(View view) {
// todo 方式四 類加載
// 類加載跳轉,可以成功。維護成本較高且容易出現人為失誤
try {
Class targetClass = Class.forName("com.xiangxue.personal.Personal_MainActivity");
Intent intent = new Intent(this, targetClass);
intent.putExtra("name", "derry");
startActivity(intent);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// personal/Personal_MainActivity getMap
// todo 方式五 全局Map
Class<?> targetActivity =
RecordPathManager.startTargetActivity("personal", "Personal_MainActivity");
startActivity(new Intent(this, targetActivity));
}
//common-PathBean.java
public class PathBean {
private String path; // personal/Personal_MainActivity
private Class clazz; // Personal_MainActivity.class
...
}
//common-RecordPathManager.java
public class RecordPathManager {
/*
* group: app,order,personal
* order:OrderMainActivity1
*/
private static Map<String, List<PathBean>> maps = new HashMap<>();
/**
* 将路徑資訊加入全局Map
*
* @param groupName 組名,如:"personal"
* @param pathName 路勁名,如:"Personal_MainActivity"
* @param clazz 類對象,如:Personal_MainActivity.class
*/
public static void addGroupInfo(String groupName, String pathName, Class<?> clazz) {
...
maps.put(groupName, list);
...
}
/**
* 隻需要告訴我,組名 ,路徑名, 就能傳回 "要跳轉的Class"
* @param groupName 組名 oder
* @param pathName 路徑名 OrderMainActivity1
* @return 跳轉目标的class類對象
*/
public static Class<?> startTargetActivity(String groupName, String pathName) {
...
// 周遊 尋找 去比對 “PathBean”對象
for (PathBean pathBean : list) {
if (pathName.equalsIgnoreCase(pathBean.getPath())) {
return pathBean.getClazz();
}
}
...
}
}
元件化二
APT
APT(Annotation Processing Tool) 處理注釋的工具,它對源代碼檔案進行檢測找出其中的Annotation ,根據注解自動生成代碼。 如果想要自定義的注解處理器能夠正常運作,必須要通過APT工具來進行處理。
通俗了解:根據規則,幫我們生成代碼、生成類文
相關類
PackageElement: 包程式元素。提供對有關包及其成員的資訊的通路
TypeElement: 類或接口程式元素。提供對有關類型及其成員的資訊的通路。
VariableElement: 字段、enum 常量、方法或構造方法參數、局部變量或異常參數
ExecutableElement: 某個類或接口的方法、構造方法或初始化程式(靜态或執行個體)
APT中用到API
getEnclosedElements() 傳回該元素直接包含的子元素
getEnclosingElement() 傳回包含該element的父element,與上一個方法相反
getKind() 傳回element的類型,判斷是哪種element
getModifiers() 擷取修飾關鍵字,如public static final等關鍵字
getSimpleName() 擷取名字,不帶包名
getQualifiedName() 擷取全名,如果是類的話,包含完整的包名路徑
getParameters() 擷取方法的參數元素,每個元素是一個VariableElement
getReturnType() 擷取方法元素的傳回值
getConstantValue() 如果屬性變量被final修飾,則可以使用該方法擷取它的 值
JavaPoet
JavaPoet是square推出開源的java代碼生成架構,提供Java Api生成.java源檔案;是我們習慣的Java面向對象OOP文法 。
傳統方式生成Java檔案:一行一行的寫入;導包都要自己寫
如果複雜的代碼生成,反而效率低下
相關類
類對象 | 說明 |
---|---|
MethodSpec | 代表構造函數,或者方法聲明 |
TypeSpec | 代表類,接口,枚舉聲明 |
FieldSpec | 代表成員變量,字段聲明 |
JavaFile | 代表頂級類的java檔案 |
ParameterSpec | 用來建立參數 |
AnnotationSpec | 用來建立注解 |
ClassName | 用來包裝一個類 |
TypeName | 類型,如添加傳回值類型是使用 TypeName.VOID |
S 字 符 串 , 如 : S 字元串,如: S字元串,如:S, ”hello ”
T 類 、 接 口 , 如 : T 類、接口,如: T類、接口,如:T, MainActivity
$N:成員變量
$L:枚舉
實戰項目
@ARouter(path = "/app/MainActivity")
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startMainActivity3(View view) {
Class startClass = MainActivity3$$$$$$$$$ARouter.findTargetClass("/app/MainActivity3");
}
}
// 通過auto-service中的@AutoService可以自動生成AutoService注解處理器,用來注冊
// 用來生成 META-INF/services/javax.annotation.processing.Processor 檔案
@AutoService(Processor.class)
@SupportedAnnotationTypes({"com.derry.arouter_annotations.ARouter"}) // 注解
@SupportedSourceVersion(SourceVersion.RELEASE_7) // 環境的版本
// 接收 安卓工程傳遞過來的參數
@SupportedOptions("student")
public class ARouterProcessor extends AbstractProcessor {
// 操作Element的工具類(類,函數,屬性,其實都是Element)
private Elements elementTool;
// type(類資訊)的工具類,包含用于操作TypeMirror的工具方法
private Types typeTool;
// Message用來列印 日志相關資訊
private Messager messager;
// 檔案生成器, 類 資源 等,就是最終要生成的檔案 是需要Filer來完成的
private Filer filer;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
elementTool = processingEnvironment.getElementUtils();
messager = processingEnvironment.getMessager();
filer = processingEnvironment.getFiler();
String value = processingEnvironment.getOptions().get("student");
}
// 服務:在編譯的時候幹活
// 坑:如果沒有在任何地方使用,次函數是不會工作的
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
// 這個代碼已經下毒了
messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>> Derry run...");
if (set.isEmpty()) {
return false; // 不幹活
}
// 循環?
// 擷取被 ARouter注解的 "類節點資訊"
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(ARouter.class);
for (Element element : elements) { // for 3 // 1 element == MainActivity 2 element == MainActivity2
/**
子產品一
package com.example.helloworld;
public final class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, JavaPoet!");
}
}
*/
// Java 萬物皆對象
// C 萬物皆指針
/*// 1.方法
MethodSpec mainMethod = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
// 增加main方法裡面的内容
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();
// 2.類
TypeSpec testClass = TypeSpec.classBuilder("DerryTest")
.addMethod(mainMethod)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.build();
// 3.包
JavaFile packagef = JavaFile.builder("com.xiangxue.test", testClass).build();
// 生成檔案
try {
packagef.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
messager.printMessage(Diagnostic.Kind.NOTE, "生成Test檔案時失敗,異常:" + e.getMessage());
}*/
// 包資訊
String packageName = elementTool.getPackageOf(element).getQualifiedName().toString();
// 擷取簡單類名,例如:MainActivity MainActivity2 MainActivity3
String className = element.getSimpleName().toString();
messager.printMessage(Diagnostic.Kind.NOTE, "被@ARetuer注解的類有:" + className);
// String className = element.getSimpleName().toString();
// 目标:要生成的檔案名稱 MainActivity$$$$$$$$$ARouter
String finalClassName = className + "$$$$$$$$$ARouter";
/**
模闆:
public class MainActivity3$$$$$$$$$ARouter {
public static Class findTargetClass(String path) {
return path.equals("/app/MainActivity3") ? MainActivity3.class : null;
}
}
*/
ARouter aRouter = element.getAnnotation(ARouter.class);
// 1.方法
MethodSpec findTargetClass = MethodSpec.methodBuilder("findTargetClass")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(Class.class)
.addParameter(String.class, "path")
// 方法裡面的内容 return path.equals("/app/MainActivity3") ? MainActivity3.class : null;
// 需要JavaPoet包裝轉型
.addStatement("return path.equals($S) ? $T.class : null",
aRouter.path(),
ClassName.get((TypeElement) element))
.build();
// 2.類
TypeSpec myClass = TypeSpec.classBuilder(finalClassName)
.addMethod(findTargetClass)
.addModifiers(Modifier.PUBLIC)
.build();
// 3.包
JavaFile packagef = JavaFile.builder(packageName, myClass).build();
// 開始生成
try {
packagef.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
messager.printMessage(Diagnostic.Kind.NOTE, "生成" + finalClassName + "檔案時失敗,異常:" + e.getMessage());
}
}
// false執行一次 true執行一次,檢測一次(内部機制)
return true;
}
}
Arouter
項目結構
app common order personal
arouter_annotation:
arouter_api:
arouter_compiler:
// app.gradle
android {
// compileOptions.encoding = "GBK"
defaultConfig {
buildConfigField("boolean", "isRelease", String.valueOf(isRelease))
// 在gradle檔案中配置選項參數值(用于APT傳參接收)必須寫在defaultConfig節點下 都是為了 傳遞給 注解處理器//解讀
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName(), packageNameForAPT: packageNameForAPT]
}
}
}
}
dependencies {
// 公共基礎庫
implementation project(":common")
// arouter 專用 注解子產品
implementation project(":arouter_annotation")
// arouter 專用 注解處理器
annotationProcessor project(':arouter_compiler')
if (isRelease) {
implementation project(":order")
implementation project(":personal")
}
}
//person.gradle
android {
defaultConfig {
buildConfigField("boolean", "isRelease", String.valueOf(isRelease))
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName(), packageNameForAPT: packageNameForAPT]
}
}
}
}
dependencies {
implementation project(":common")
implementation project(":arouter_annotation")
annotationProcessor project(':arouter_compiler')
}
//order.gradle
android {
buildConfigField("boolean", "isRelease", String.valueOf(isRelease))
javaCompileOptions {
annotationProcessorOptions {
// this.project.getName() == order
// this.getProject().getName() == order
arguments = [moduleName: project.getName(), packageNameForAPT: packageNameForAPT]
}
}
}
}
dependencies {
implementation project(":common")
implementation project(":arouter_annotation")
annotationProcessor project(':arouter_compiler')
}
//common.gradle
android {
}
dependencies {
// 因為每一個 “子Module”都依賴了 common,所有當我們在 common中依賴 arouter_api(柱狀)
// 就等于 全部都依賴了 arouter_api
api project(":arouter_api")
}
//arouter_compiler.gradle
apply plugin: 'java-library'
dependencies {
// AS 4.3.1 -> 4.0.1 沒有問題
// As-3.4.1 + gradle-5.1.1-all + 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'
// 幫助我們通過類調用的形式來生成Java代碼
implementation "com.squareup:javapoet:1.9.0"
// 引入annotation,處理@ARouter注解
implementation project(':arouter_annotation')
}
// java控制台輸出中文亂碼
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
sourceCompatibility = "7"
targetCompatibility = "7"
//arouter_api.gradle
android {
}
dependencies {
// 引入注解中RouterBean對象(java項目才有javax.lang包)
implementation project(':arouter_annotation')
}
//arouter_annotation.gradle
apply plugin: 'java-library'
// java控制台輸出中文亂碼
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
sourceCompatibility = "7"
targetCompatibility = "7"
元件化三
跳轉activity
//具體實作類會new一個hashMaep,将所有的RouterBean添加進去後,傳回;
public interface ARouterPath {
//key:"/order/Order_MainActivity"
//value: Order_MainActivity.class RouterBean
Map<String, RouterBean> getPathMap();
}
public interface ARouterGroup {
//key:"order/app/personal"
//value:系列的order組下面所有的(path---class)
Map<String, Class<? extends ARouterPath>> getGroupMap();
}
//APT中判斷是否Activity的子類
// 通過Element工具類,擷取Activity,Callback類型
TypeElement activityType = elementTool.getTypeElement(ProcessorConfig.ACTIVITY_PACKAGE);
// 顯示類資訊(擷取被注解的節點,類節點)這也叫自描述 Mirror android.app.Activity描述資訊
TypeMirror activityMirror = activityType.asType();
TypeMirror elementMirror = element.asType(); // Main2Activity的具體詳情
// typeTool.isSubtype方法判斷
if (typeTool.isSubtype(elementMirror, activityMirror)) {
routerBean.setTypeEnum(RouterBean.TypeEnum.ACTIVITY);
} else {
// 不比對抛出異常,這裡謹慎使用!考慮維護問題
throw new RuntimeException("@ARouter注解目前僅限用于Activity類之上");
}
//APT生成帶泛型的class
// Map<String, RouterBean>
TypeName methodReturn = ParameterizedTypeName.get(
ClassName.get(Map.class), // Map
ClassName.get(String.class), // Map<String,
ClassName.get(RouterBean.class) // Map<String, RouterBean>
);
// Class<? extends ARouterPath>> 難度
ParameterizedTypeName.get(ClassName.get(Class.class),
// ? extends ARouterPath
WildcardTypeName.subtypeOf(ClassName.get(pathType)))
//繼承和重寫方法
TypeSpec.classBuilder(finalClassName) // 類名
.addSuperinterface(ClassName.get(pathType)) // 實作ARouterLoadPath接口 implements ARouterPath==pathType
MethodSpec.methodBuilder(ProcessorConfig.PATH_METHOD_NAME)
.addAnnotation(Override.class) // 給方法上添加注解 @Override
使用
//app
//MainActivity.java
public void jumpPersonal(View view) {
// 以前是這樣跳轉
/*Intent intent = new Intent(this, Personal_MainActivity.class);
intent.putExtra("name", "derry");
startActivity(intent);*/
// 現在是這樣跳轉 目前還要寫這麼多代碼,是不是非常累
// TODO 最終的成效:使用者 一行代碼搞定,同時還可以傳遞參數,同時還可以懶加載
ARouter$$Group$$personal group$$personal = new ARouter$$Group$$personal();
Map<String, Class<? extends ARouterPath>> groupMap = group$$personal.getGroupMap();
Class<? extends ARouterPath> myClass = groupMap.get("personal");
try {
ARouter$$Path$$personal path = (ARouter$$Path$$personal) myClass.newInstance();
Map<String, RouterBean> pathMap = path.getPathMap();
RouterBean bean = pathMap.get("/personal/Personal_MainActivity");
if (bean != null) {
Intent intent = new Intent(this, bean.getMyClass());
startActivity(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
元件化四
跳轉傳遞參數,通過懶加載的方法,在目标Activity的成員上加上對應的注解;通過intent傳遞;
1.arouter_annotation 添加注解 Parameter
2.arouter_api ParaneterGet标準規則的定義
3.arouter_compiler ParameterProcessor注解處理器生成剛剛分析的模闆代碼
4.arouter_api ParamaterManager參數管理器的編寫
ARouterProcessor.java :生成檔案,使得這個檔案的方法産生一個map,這個map傳回之前存儲了所有被@ARoute注解的類的calss。key是ARoute注解中傳入的pathj。
RouterManager:構造時會傳入path。通過截取path拼接檔案名,查找ParameterProcessor生成的檔案,調用方法擷取已經存了class的map。再通過map,通過key:path查找到對應的class。可以完成跳轉,通過with方法傳值,通過intent傳輸。
ParameterProcessor.java:生成檔案,使得這個檔案的方法可以對傳入的參數中的對象中的成員指派。這些被指派的成員都是被@Parameter注解的。賦的值是通過取出intent中的資料。字段的名字,要與intent傳值是的key對應。
ParameterManager:調用方法時會傳入要指派成員的對象,通過對象類名拼接後直接得到ARouterProcessor生成檔案的名字,可以建立對象,調用對應的方法,指派。
public interface ParameterGet {
/**
* 目标對象.屬性名 = getIntent().屬性類型... 完成指派操作
* @param targetParameter 目标對象:例如:MainActivity 中的那些屬性
*/
void getParameter(Object targetParameter);
}
//arouter_compiler
//ParameterProcessor.java
// 臨時map,存放被@Parameter注解的屬性集合,生成類檔案時周遊
// key:類節點, value:被@Parameter注解的屬性集合
private Map<TypeElement, List<Element>> tempParameterMap = new HashMap<>();
// 注解在屬性的上面,屬性節點父節點 是 類節點
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
//implements ParameterGet 實作ParameterLoad接口
TypeSpec.classBuilder(finalClassName) .addSuperinterface(ClassName.get(parameterType))
//ParameterFactory.java
// 通過方法參數體建構方法體:就是重寫public void getParameter(Object target) {}
method = MethodSpec.methodBuilder(ProcessorConfig.PARAMETER_METHOD_NAME)
.addAnnotation(Override.class);
public void buildStatement(Element element) {
// 周遊注解的屬性節點 生成函數體
TypeMirror typeMirror = element.asType();
// 擷取 TypeKind 枚舉類型的序列号
int type = typeMirror.getKind().ordinal();
...
if (type == TypeKind.INT.ordinal()) {
methodContent += "getIntExtra($S, " + finalValue + ")"; // 有預設值
} else if (type == TypeKind.BOOLEAN.ordinal()) {
// t.s = t.getIntent().getBooleanExtra("isSuccess", t.age);
methodContent += "getBooleanExtra($S, " + finalValue + ")"; // 有預設值
} else { // String 類型,沒有序列号的提供 需要我們自己完成
// t.s = t.getIntent.getStringExtra("s");
// typeMirror.toString() java.lang.String
if (typeMirror.toString().equalsIgnoreCase(ProcessorConfig.STRING)) {
// String類型
methodContent += "getStringExtra($S)"; // 沒有預設值
}
}
...
}
//arouter_api
//ParameterManager.java
// 使用者 隻需要調用這一個方法,就可以進行參數的接收
public void loadParameter(Activity activity) { // 必須拿到 Personal_MainActivity
String className = activity.getClass().getName();
ParameterGet parameterLoad = cache.get(className);
if (null == parameterLoad) { // 緩存裡面沒東東 提高性能
// 拼接 如:Order_MainActivity + $$Parameter
try {
// 類加載Personal_MainActivity + $$Parameter
Class<?> aClass = Class.forName(className + FILE_SUFFIX_NAME);
// 用接口parameterLoad = 接口的實作類Personal_MainActivity
parameterLoad = (ParameterGet) aClass.newInstance(); cache.put(className, parameterLoad); // 儲存到緩存
} catch (Exception e) {
e.printStackTrace();
}
}
parameterLoad.getParameter(activity); // 最終的執行 會執行我們生成的類
}
//RouterManager.java
// 真正的導航
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public Object navigation(Context context, BundleManager bundleManager) {
// 例如:尋找 ARouter$$Group$$personal 尋址 ARouter$$Group$$order ARouter$$Group$$app
String groupClassName = context.getPackageName() + "." + FILE_GROUP_NAME + group;
try {
// TODO 第一步 讀取路由組Group類檔案
...
// TODO 第二步 讀取路由Path類檔案
...
// TODO 第三步 跳轉
if (loadPath != null) { // 健壯
// 最後才執行操作
RouterBean routerBean = loadPath.getPathMap().get(path);
if (routerBean != null) {
switch (routerBean.getTypeEnum()) {
case ACTIVITY:
Intent intent = new Intent(context, routerBean.getMyClass());
intent.putExtras(bundleManager.getBundle()); // 攜帶參數
context.startActivity(intent, bundleManager.getBundle());
break;
//同學們可以自己擴充 類型
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
使用
//app
//MainActivity.java
public void jumpPersonal(View view) {
// 使用我們自己寫的路由 跳轉互動
RouterManager.getInstance()
.build("/personal/Personal_MainActivity")
.withString("name", "史甄湘")
.withString("sex", "男")
.withInt("age", 99)
.navigation(this);
}
//person
//MainActivity.java
@Parameter
String name; // 序列号 String
@Parameter
String sex;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.personal_activity_main);
// 模仿人家了 bind(this);
ParameterManager.getInstance().loadParameter(this);
}
元件化五
傳遞圖檔,傳遞Bean,調用方法的使用方法都是用懶加載的方法進行的;在目标Activity的成員上加上@parameter注解;而要傳遞的資料定義成Call,用@Arouter 注解;
1.arouter_api Call 标準規則的定義
2.common OrderDrawable 繼承Call order組圖檔标準規則的定義
3.order OrderDrawableImpl 最終的具體實作交給具體子產品order
4.arouter_compiler ARouterProcessor 修改代碼
5.app MainActivity 使用圖檔到ImageView 有問題 進入第六步
6.arouter_compiler ParameterProcessor / ParameterFactory 修改代碼
7.arouter_api RouterManager / BundleManager 修改代碼
ARouterProcessor.java :生成檔案,使得這個檔案的方法産生一個map,這個map傳回之前存儲了所有被@ARoute注解的類的calss。key是ARoute注解中傳入的path。
RouterManager:構造時會傳入path。通過截取path拼接檔案名,查找ParameterProcessor生成的檔案,調用方法擷取已經存了class的map。再通過map,通過key:path查找到對應的class。可以完成跳轉,通過with方法傳值,通過intent傳輸。如果class是Call,那麼會執行個體化對象,并傳回
ParameterProcessor.java:生成檔案,使得這個檔案的方法可以對傳入的參數中的對象中的成員指派。這些被指派的成員都是被@Parameter注解的。賦的值是通過取出intent中的資料。字段的名字,要與intent傳值是的key對應。如果是Call類型,那麼值不是從intent中擷取,而是調用RouterManager的navigation方法擷取;這個時候取出Parameter注解中的值當時做path傳入RouterManager。
ParameterManager:調用方法時會傳入要指派成員的對象,通過對象類名拼接後直接得到ARouterProcessor生成檔案的名字,可以建立對象,調用對應的方法,指派。
//arouter_api-Call.java
public interface Call {
}
//common-OrderDrawable.java
public interface OrderDrawable extends Call {
int getDrawable();
}
//order-OrderDrawableImpl.java
// order 自己決定 自己的暴漏;
//使用@ARouter,現在@ARouter被用在繼承Activity和Call兩個地方
@ARouter(path = "/order/getDrawable")
public class OrderDrawableImpl implements OrderDrawable {
@Override
public int getDrawable() {
return R.drawable.ic_ac_unit_black_24dp;
}
}
//arouter_compiler-ARouterProcessor.java
// TODO 新增點1
TypeElement callType = elementTool.getTypeElement(ProcessorConfig.CALL);
TypeMirror callMirror = callType.asType(); // 自描述 callMirror
if (typeTool.isSubtype(elementMirror, activityMirror)) {
routerBean.setTypeEnum(RouterBean.TypeEnum.ACTIVITY);
} else if (typeTool.isSubtype(elementMirror, callMirror)) { // TODO 新增點2
routerBean.setTypeEnum(RouterBean.TypeEnum.CALL);
}
//arouter_compiler
//ParameterProcessor.java
// 将elementUtils傳入ParameterFactory
ParameterFactory factory = new ParameterFactory.Builder(parameterSpec)
.setMessager(messager)
.setElementUtils(elementUtils) // TODO 新增點
.setTypeUtils(typeUtils)
.setClassName(className)
.build();
//ParameterFactory.java
if (typeMirror.toString().equalsIgnoreCase(ProcessorConfig.STRING)) {
// String類型
methodContent += "getStringExtra($S)"; // 沒有預設值
} else if (typeUtils.isSubtype(typeMirror, callMirror)) { // 你居然實作了Call接口
// t.orderDrawable = (OrderDrawable)RouterManager.getInstance().build("/order/getDrawable").navigation(t);
methodContent = "t." + fieldName + " = ($T) $T.getInstance().build($S).navigation(t)";
method.addStatement(methodContent,
TypeName.get(typeMirror),
ClassName.get(ProcessorConfig.AROUTER_API_PACKAGE,
ProcessorConfig.ROUTER_MANAGER),
annotationValue);
return;
} else { // 對象的傳輸
methodContent = "t.getIntent().getSerializableExtra($S)";
}
//arouter_api
//RouterManager.java
public Object navigation(Context context, BundleManager bundleManager) {
...
switch (routerBean.getTypeEnum()) {
case ACTIVITY:
Intent intent = new Intent(context, routerBean.getMyClass());
intent.putExtras(bundleManager.getBundle());
context.startActivity(intent);
break;
case CALL:
// OrderAddressImpl.class OrderBean getOrderBean
// OrderUserImpl BaseUser實體
Class<?> clazz = routerBean.getMyClass();
Call call = (Call) clazz.newInstance();
bundleManager.setCall(call);
return bundleManager.getCall();
//同學們可以自己擴充 類型
}
...
}
使用
//使用@ARouter,現在@ARouter被用在繼承Activity和Call兩個地方
@ARouter(path = "/order/getDrawable")
public class OrderDrawableImpl implements OrderDrawable {
@Override
public int getDrawable() {
return R.drawable.ic_ac_unit_black_24dp;
}
}
//app-MainActivity
@Parameter(name = "/order/getDrawable")
OrderDrawable orderDrawable; // 公共基礎庫common
// 拿order子產品的 網絡請求功能
@Parameter(name = "/order/getOrderBean")
OrderAddress orderAddress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 懶加載方式,跳到哪加載哪個類
ParameterManager.getInstance().loadParameter(this);
// app子產品本來就可以直接加載其他子產品的資源 personal
// 拿到 order子產品的圖檔 在app子產品展示
int drawableId = orderDrawable.getDrawable();
ImageView img = findViewById(R.id.img);
img.setImageResource(drawableId);
}
補充
//order子產品生成的類
public class ARouter$$Group$$order implements ARouterGroup {
@Override
public Map<String, Class<? extends ARouterPath>> getGroupMap() {
Map<String, Class<? extends ARouterPath>> groupMap = new HashMap<>();
groupMap.put("order", ARouter$$Path$$order.class);
return groupMap;
}
}
public class ARouter$$Path$$order implements ARouterPath {
@Override
public Map<String, RouterBean> getPathMap() {
Map<String, RouterBean> pathMap = new HashMap<>();
pathMap.put("/order/getOrderBean", RouterBean.create(RouterBean.TypeEnum.CALL, OrderAddressImpl.class, "/order/getOrderBean", "order"));
pathMap.put("/order/getDrawable", RouterBean.create(RouterBean.TypeEnum.CALL, OrderDrawableImpl.class, "/order/getDrawable", "order"));
pathMap.put("/order/getUserInfo", RouterBean.create(RouterBean.TypeEnum.CALL, OrderUserImpl.class, "/order/getUserInfo", "order"));
pathMap.put("/order/Order_MainActivity", RouterBean.create(RouterBean.TypeEnum.ACTIVITY, Order_MainActivity.class, "/order/Order_MainActivity", "order"));
return pathMap;
}
}
public class Order_MainActivity$$Parameter implements ParameterGet {
@Override
public void getParameter(Object targetParameter) {
Order_MainActivity t = (Order_MainActivity) targetParameter;
t.name = t.getIntent().getStringExtra("name");
}
}
//Personal子產品生成的類
public class Personal_MainActivity$$Parameter implements ParameterGet {
@Override
public void getParameter(Object targetParameter) {
Personal_MainActivity t = (Personal_MainActivity) targetParameter;
t.name = t.getIntent().getStringExtra("name");
t.sex = t.getIntent().getStringExtra("sex");
t.age = t.getIntent().getIntExtra("age", t.age);
t.student=(Student)t.getIntent().getSerializableExtra("student");
t.orderDrawable = (OrderDrawable) RouterManager.getInstance().build("/order/getDrawable").navigation(t);
t.orderAddress = (OrderAddress) RouterManager.getInstance().build("/order/getOrderBean").navigation(t);
}
}