天天看點

元件化

元件化一

簡介

單一分層問題: 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);
  }
}