ARouter是什么?
ARouter是阿里開源的一款android路由框架言询,幫助 Android App 進行組件化改造的路由框架 —— 支持模塊間的路由、通信夫啊、解耦;結(jié)合路由可以實現(xiàn)組件化辆憔。
ARouter接入指北
完整Arouter接入指南撇眯,ARouter重度用戶可以跳過熊榛,直接往后看
- 第一步腕巡,根build.gradle設(shè)置使用arouter-register
apply plugin: 'com.alibaba.arouter'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "com.alibaba:arouter-register:?"
}
}
- 第二步绘沉,創(chuàng)建baselib,并加入dependencies
api 'com.alibaba:arouter-api:x.x.x'
- 第三步择懂,創(chuàng)建組件module困曙,例如login 或者setting 組件
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
}
dependencies {
// 替換成最新版本, 需要注意的是api
// 要與compiler匹配使用日矫,均使用最新版可以保證兼容
//compile 'com.alibaba:arouter-api:x.x.x' 此移動到baselib中
api project(path: ':baselib')
annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
...
}
- 第四步哪轿,通過注解@Route 注冊頁面
// 在支持路由的頁面上添加注解(必選)
// 這里的路徑需要注意的是至少需要有兩級窃诉,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
...
}
- 第五步,初始化
if (isDebug()) { // 這兩行必須寫在init之前珊膜,否則這些配置在init過程中將無效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 開啟調(diào)試模式(如果在InstantRun模式下運行车柠,必須開啟調(diào)試模式塑猖!線上版本需要關(guān)閉,否則有安全風(fēng)險)
}
ARouter.init(mApplication); // 盡可能早,推薦在Application中初始化
- 第六步羊苟,使用ARouter
ARouter.getInstance().build("/test/activity").navigation();
ARouter比傳統(tǒng)Intent有哪些優(yōu)點
傳統(tǒng)intent的優(yōu)點
- 輕量
- 簡單
傳統(tǒng)intent的缺點
- 跳轉(zhuǎn)過程無法控制,一旦調(diào)用了
startActivity(Intent)
便交由系統(tǒng)執(zhí)行令花,中間過程無法插手 - 跳轉(zhuǎn)失敗無法捕獲兼都、降級俯抖,出現(xiàn)問題直接拋出異常
- 顯示Intent中因為存在直接的類依賴關(guān)系瓦胎,導(dǎo)致耦合嚴重
startActivity(new Intent(MainActivity.this, LoginActivity.class));//強依賴LoginActivity
- 隱式Intent中會出現(xiàn)規(guī)則集中式的管理搔啊,導(dǎo)致協(xié)作困難负芋,都需要在Manifest中進行配置,導(dǎo)致擴展性比較差
//隱式 比 顯式更強一點莽龟,可以在兩個無關(guān)子module 之間跳轉(zhuǎn)毯盈,由于顯式無法引入包搂赋,所以無法完成跳轉(zhuǎn)
Intent intent = new Intent();
intent.setClassName(MainActivity.this,"com.cnn.loginplugin.ui.login.LoginActivity");//設(shè)置包路徑
startActivity(intent);
ARouter優(yōu)點
- 模塊間通信(后面講原理)
- 支持url 跳轉(zhuǎn)
build("/test/activity").navigation()
- 支持攔截器
// 比較經(jīng)典的應(yīng)用就是在跳轉(zhuǎn)過程中處理登陸事件脑奠,這樣就不需要在目標頁重復(fù)做登陸檢查
// 攔截器會在跳轉(zhuǎn)之間執(zhí)行,多個攔截器會按優(yōu)先級順序依次執(zhí)行
@Interceptor(priority = 8, name = "測試用攔截器")
public class TestInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
...
callback.onContinue(postcard); // 處理完成轰豆,交還控制權(quán)
// callback.onInterrupt(new RuntimeException("我覺得有點異常")); // 覺得有問題秒咨,中斷路由流程
// 以上兩種至少需要調(diào)用其中一種雨席,否則不會繼續(xù)路由
}
@Override
public void init(Context context) {
// 攔截器的初始化陡厘,會在sdk初始化的時候調(diào)用該方法特占,僅會調(diào)用一次
}
}
- 參數(shù)注入是目,@Autowired注解實現(xiàn)懊纳,更方便,需要配合
ARouter.getInstance().inject(this);
一起使用
@Autowired
public String name;
@Autowired
int age;
// 通過name來映射URL中的不同參數(shù)
@Autowired(name = "girl")
boolean boy;
// 支持解析自定義對象冤今,URL中使用json傳遞
@Autowired
TestObj obj;
// 使用 withObject 傳遞 List 和 Map 的實現(xiàn)了
// Serializable 接口的實現(xiàn)類(ArrayList/HashMap)
// 的時候戏罢,接收該對象的地方不能標注具體的實現(xiàn)類類型
// 應(yīng)僅標注為 List 或 Map龟糕,否則會影響序列化中類型
// 的判斷, 其他類似情況需要同樣處理
@Autowired
List<TestObj> list;
@Autowired
Map<String, List<TestObj>> map;
- 支持外部url 跳轉(zhuǎn)
<activity android:name=".SchemeFilterActivity">
<!-- Scheme -->
<intent-filter>
<data
android:host="www.nativie.com"
android:scheme="arouter"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
- 簡單demo讲岁,github做簡單靜態(tài)界面服務(wù)器催首,并部署到https://oslanka.github.io/statichtml.github.io/郎任,手機瀏覽器打開备籽,并點擊href實現(xiàn)html打通原生车猬,按道理來說珠闰,所有未攔截的ARouter路徑伏嗜,均可被web瀏覽器跳轉(zhuǎn),html代碼如下:
<html>
<body>
<p><a >測試跳轉(zhuǎn)</a> </p>
<p><a href="arouter://www.nativie.com/login/login">跳轉(zhuǎn)登錄android-ARouter</a></p>
<p><a href="arouter://www.nativie.com/login/login?username=admin&password=123456">跳轉(zhuǎn)登錄android-ARouter 帶參數(shù)</a></p>
<p><a href="arouter://www.nativie.com/setting/setting">跳轉(zhuǎn)android-ARouter 設(shè)置界面</a></p>
<p><a href="arouter://www.nativie.com/web/web">跳轉(zhuǎn)android-ARouter 設(shè)置界面</a></p>
<p><a href="arouter://www.nativie.com/test/test">跳轉(zhuǎn)android-ARouter 錯誤路徑</a></p>
</body>
</html>
關(guān)于攔截器
- 攔截器(攔截跳轉(zhuǎn)過程,面向切面編程)
- 什么是面向切面編程AOP军熏?AOP為Aspect Oriented Programming的縮寫荡澎,意為:面向切面編程摩幔,通過預(yù)編譯方式和運行期間動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護的一種技術(shù)热鞍。AOP是OOP的延續(xù),是軟件開發(fā)中的一個熱點偷办,也是Spring框架中的一個重要內(nèi)容椒涯,是函數(shù)式編程的一種衍生范型废岂。利用AOP可以對業(yè)務(wù)邏輯的各個部分進行隔離湖苞,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性镐作,同時提高了開發(fā)的效率
// 攔截器會在跳轉(zhuǎn)之前執(zhí)行该贾,多個攔截器會按優(yōu)先級順序依次執(zhí)行
@Interceptor(priority = 8, name = "測試用攔截器")
public class TestInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
...
callback.onContinue(postcard); // 處理完成杨蛋,交還控制權(quán)
// callback.onInterrupt(new RuntimeException("我覺得有點異常")); // 覺得有問題六荒,中斷路由流程
// 以上兩種至少需要調(diào)用其中一種掏击,否則不會繼續(xù)路由
}
@Override
public void init(Context context) {
// 攔截器的初始化秩铆,會在sdk初始化的時候調(diào)用該方法殴玛,僅會調(diào)用一次
}
}
動態(tài)路由
- 動態(tài)注冊路由信息 適用于部分插件化架構(gòu)的App以及需要動態(tài)注冊路由信息的場景滚粟,可以通過 ARouter 提供的接口實現(xiàn)動態(tài)注冊 路由信息凡壤,目標頁面和服務(wù)可以不標注 @Route 注解亚侠,注意:同一批次僅允許相同 group 的路由信息注冊
ARouter.getInstance().addRouteGroup(new IRouteGroup() {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/dynamic/activity", // path
RouteMeta.build(
RouteType.ACTIVITY, // 路由信息
TestDynamicActivity.class, // 目標的 Class
"/dynamic/activity", // Path
"dynamic", // Group, 盡量保持和 path 的第一段相同
0, // 優(yōu)先級硝烂,暫未使用
0 // Extra,用于給頁面打標
)
);
}
});
ARouter詳細API
// 構(gòu)建標準的路由請求除抛,并指定分組
ARouter.getInstance().build("/home/main", "ap").navigation();
// 構(gòu)建標準的路由請求母截,通過Uri直接解析
Uri uri;
ARouter.getInstance().build(uri).navigation();
// 構(gòu)建標準的路由請求微酬,startActivityForResult
// navigation的第一個參數(shù)必須是Activity颗管,第二個參數(shù)則是RequestCode
ARouter.getInstance().build("/home/main", "ap").navigation(this, 5);
// 指定Flag
ARouter.getInstance()
.build("/home/main")
.withFlags();
.navigation();
// 獲取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
// 對象傳遞
ARouter.getInstance()
.withObject("key", new TestObj("Jack", "Rose"))
.navigation();
// 使用綠色通道(跳過所有的攔截器)
ARouter.getInstance().build("/home/main").greenChannel().navigation();
原理探索
- ARouter.init 時垦江,通過獲取
/data/app/包名/base.apk
來篩選出ARouter生成的類比吭,如下圖衩藤。
- 對于Activity類型赏表,跳轉(zhuǎn)
ARouter.getInstance().build("/login/login").navigation();
瓢剿,最終執(zhí)行的是间狂,如下:
**
* Start activity
*
* @see ActivityCompat
*/
private void startActivity(int requestCode, Context currentContext, Intent intent, Postcard postcard, NavigationCallback callback) {
if (requestCode >= 0) { // Need start for result
if (currentContext instanceof Activity) {//啟動context 為Activity
ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
} else {
// 啟動context 為Application 時鉴象,不支持requestCode
logger.warning(Consts.TAG, "Must use [navigation(activity, ...)] to support [startActivityForResult]");
}
} else {//啟動context 為Application
ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
}
if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version.
((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
}
if (null != callback) { // Navigation over.
callback.onArrival(postcard);
}
}
- 兩個無關(guān)的module 如何跳轉(zhuǎn)的呢炼列?我們發(fā)現(xiàn)最終執(zhí)行startActivity時俭尖,所用的context為Application,思路是這樣的焰望,子module啟動另外無關(guān)子module時熊赖,將執(zhí)行權(quán)震鹉,交還給主進程/主程序去處理
- 打開生成路由文檔,AROUTER_GENERATE_DOC="enable",會生成arouter-map-of-xx.json和3個java文件
// 更新 build.gradle, 添加參數(shù) AROUTER_GENERATE_DOC = enable
// 生成的文檔路徑 : build/generated/ap_generated_sources/(debug or release)/com/alibaba/android/arouter/docs/arouter-map-of-${moduleName}.json
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: "enable"]
}
}
}
}
//ARouter映射關(guān)系如何生成?Generated出三個文件
//ARouter$$Group$$login
//ARouter$$Providers$$loginplugin
//ARouter$$Root$$loginplugin
atlas.put("/login/login", RouteMeta.build(RouteType.ACTIVITY, LoginActivity.class, "/login/login", "login", new java.util.HashMap<String, Integer>(){{put("password", 8); put("username", 8); }}, -1, -2147483648));
//map 存映射關(guān)系
//static Map<String, RouteMeta> routes = new HashMap<>();
- 以上三個文件是如何生成的呢浆兰?APT是Annotation Processing Tool的簡稱,即注解處理工具簸呈,apt是在編譯期對代碼中指定的注解進行解析蜕便,然后做一些其他處理(如通過javapoet生成新的Java文件)ARouter使用了兩個庫
auto-service
javapoet
轿腺,來實現(xiàn)從注解到代碼的注入段直,其中auto-service
為注解處理器的庫鸯檬,javapoet
為代碼生成器
通過例子了解APT
首先我們了解一下元注解喧务,meta-annotation(元注解)
- @Target
TYPE, // 類功茴、接口坎穿、枚舉類
FIELD, // 成員變量(包括:枚舉常量)
METHOD, // 成員方法
PARAMETER, // 方法參
CONSTRUCTOR, // 構(gòu)造方法
LOCAL_VARIABLE, // 局部變量
ANNOTATION_TYPE, // 注解類
PACKAGE, // 可用于修飾:包
TYPE_PARAMETER, // 類型參數(shù),JDK 1.8 新增
TYPE_USE // 使用類型的任何地方篮绿,JDK 1.8 新增
```
- @Retention
```java
SOURCE, 只在本編譯單元的編譯過程中保留亲配,并不寫入Class文件中惶凝。
CLASS, 在編譯的過程中保留并且會寫入Class文件中,但是JVM在加載類的時候不需要將其加載為運行時可見的(反射可見)的注解==是JVM在加載類時反射不可見苍鲜。
RUNTIME 在編譯過程中保留坡贺,會寫入Class文件遍坟,并且JVM加載類的時候也會將其加載為反射可見的注解愿伴。
```
- @Documented 注解的作用是:描述在使用 javadoc 工具為類生成幫助文檔時是否要保留其注解信息.
- @Inherited 注解的作用是:使被它修飾的注解具有繼承性(如果某個類使用了被@Inherited修飾的注解隔节,則其子類將自動具有該注解)
- 通過元注解我們定義自己的注解
- [AutoService 注解處理器](https://github.com/google/auto/tree/master/service)
注解處理器是一個在javac中的怎诫,用來編譯時掃描和處理的注解的工具贷痪。你可以為特定的注解劫拢,注冊你自己的注解處理器舱沧。到這里熟吏,我假設(shè)你已經(jīng)知道什么是注解,并且知道怎么申明的一個注解類型哆料。
一個注解的注解處理器东亦,以Java代碼(或者編譯過的字節(jié)碼)作為輸入唬渗,生成文件(通常是.java文件)作為輸出镊逝。
- 虛處理器`AbstractProcessor`
- `init(ProcessingEnvironment env)`: 【核心】
每一個注解處理器類都必須有一個空的構(gòu)造函數(shù)撑蒜。然而座菠,這里有一個特殊的init()方法浴滴,它會被注解處理工具調(diào)用升略,并輸入`ProcessingEnviroment`參數(shù)品嚣。`ProcessingEnviroment`提供很多有用的工具類`Elements`,`Types`和`Filer`
- `process(Set< ? extends TypeElement> annotations, RoundEnvironment env)`:【核心】
這相當于每個處理器的主函數(shù)main()翰撑。你在這里寫你的掃描额嘿、評估和處理注解的代碼册养,以及生成Java文件
- `getSupportedAnnotationTypes()`
這里你必須指定,這個注解處理器是注冊給哪個注解的
- `getSupportedSourceVersion()`
用來指定你使用的Java版本靠闭。通常這里返回`SourceVersion.latestSupported()`
- APT 所用的代碼生成器:**[JavaPoet](https://github.com/square/javapoet)** is a Java API for generating `.java` source files.(JavaPoet 是一個java api 愧膀,為了生成 .java源文件的)
- 官方helloworld
```java
MethodSpec main = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
.build();
javaFile.writeTo(System.out);
- 通過以上可生成以下java 文件
package com.example.helloworld;
public final class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, JavaPoet!");
}
}
-
JavaPoet
主要api
- JavaFile 用于構(gòu)造輸出包含一個頂級類的Java文件
- TypeSpec 生成類檩淋,接口蟀悦,或者枚舉
- MethodSpec 生成構(gòu)造函數(shù)或方法
- FieldSpec 生成成員變量或字段
- ParameterSpec 用來創(chuàng)建參數(shù)
- AnnotationSpec 用來創(chuàng)建注解
-
JavaPoet
主要占位符
- $L(for Literals) 執(zhí)行結(jié)構(gòu)的字符或常見類型日戈,或TypeSpec, $S(for Strings) 字符, $T(for Types) 類, $N(for Names) 方法 等標識符
$L>$S
//1.Pass an argument value for each placeholder in the format string to `CodeBlock.add()`. In each example, we generate code to say "I ate 3 tacos"
CodeBlock.builder().add("I ate $L $L", 3, "tacos")
//2.When generating the code above, we pass the hexDigit() method as an argument to the byteToHex() method using $N:
MethodSpec byteToHex = MethodSpec.methodBuilder("byteToHex")
.addParameter(int.class, "b")
.returns(String.class)
.addStatement("char[] result = new char[2]")
.addStatement("result[0] = $N((b >>> 4) & 0xf)", hexDigit)
.addStatement("result[1] = $N(b & 0xf)", hexDigit)
.addStatement("return new String(result)")
.build();
//=======================
public String byteToHex(int b) {
char[] result = new char[2];
result[0] = hexDigit((b >>> 4) & 0xf);
result[1] = hexDigit(b & 0xf);
return new String(result);
}
//$T for Types
//We Java programmers love our types: they make our code easier to understand. And JavaPoet is on board. It has rich built-in support for types, including automatic generation of import statements. Just use $T to reference types:
.addStatement("return new $T()", Date.class)== return new Date();
實戰(zhàn)-自定義簡易版路由-CRouter
- 新建name-annotation javaLib份氧,定義CRoute注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface CRoute {
String path();
}
- 新建name-compiler javaLib
1.
dependencies {
implementation project(path: ':TestRouter-annotation')
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'
compileOnly 'com.google.auto.service:auto-service-annotations:1.0-rc7'
implementation 'com.squareup:javapoet:1.8.0'
}
2.@AutoService(Processor.class)
public class TestRouteProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
//dosomething
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//dosomething
}
}
- 業(yè)務(wù)module執(zhí)行順序如下
1. annotationProcessor project(':TestRouter-compiler')
implementation project(':TestRouter-annotation')
2.添加注解@CRoute(path = "/csetting/csetting")
3.編譯運行
4.業(yè)務(wù)module apt 生成的java 文件,如下:
public final class C$csettingC$csettingHelloWorld {
public static String holder = "/csetting/csetting:com.cnn.settingplugin.SettingsActivity";
public static void main(String[] args) {
System.out.println("Hello, JavaPoet!");
}
}
- 參考
ARouter-init
方法钮糖,寫出我們CRouter-init
/**
* Init, it must be call before used router.
*/
public static void init(Application application) {
if (!hasInit) {
CRouter.application=application;
hasInit=true;
try {
getFileNameByPackageName(application, ROUTE_ROOT_PAKCAGE);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
-
利用反射獲取到注解對應(yīng)映射關(guān)系,并參考ARouter存入HashMap
-
通過隱式啟動Activity模擬跳轉(zhuǎn)
到此我們模擬出簡易版本的ARouter,完整自定義CRouter
/**
* Created by caining on 7/29/21 16:09
* E-Mail Address:cainingning@#
*/
public class CRouter {
private volatile static CRouter instance = null;
private volatile static boolean hasInit = false;
private static Application application;
public static final String ROUTE_ROOT_PAKCAGE = "com.cnn.crouter";
private static Map<String ,String> mapHolder = new HashMap<>();
/**
* Init, it must be call before used router.
*/
public static void init(Application application) {
if (!hasInit) {
CRouter.application=application;
hasInit=true;
try {
getFileNameByPackageName(application, ROUTE_ROOT_PAKCAGE);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Get instance of router. A
* All feature U use, will be starts here.
*/
public static CRouter getInstance() {
if (!hasInit) {
throw new InitException("ARouter::Init::Invoke init(context) first!");
} else {
if (instance == null) {
synchronized (CRouter.class) {
if (instance == null) {
instance = new CRouter();
}
}
}
return instance;
}
}
public void navigation(String path) {
startActivity(path);
}
private void startActivity(String path) {
String classPath
= mapHolder.get(path);
if (!TextUtils.isEmpty(classPath)) {
Intent intent = new Intent();
intent.setClassName(application, classPath);//設(shè)置包路徑
ActivityCompat.startActivity(application, intent, null);
}else {
Toast.makeText(application, "路徑空啦", Toast.LENGTH_SHORT).show();
}
}
/**
* 通過指定包名,掃描包下面包含的所有的ClassName
*
* @param context U know
* @param packageName 包名
* @return 所有class的集合
*/
private static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException {
final Set<String> classNames = new HashSet<>();
List<String> paths = getSourcePaths(context);
final CountDownLatch parserCtl = new CountDownLatch(paths.size());
for (final String path : paths) {
DefaultPoolExecutor.getInstance().execute(new Runnable() {
@Override
public void run() {
DexFile dexfile = null;
try {
if (path.endsWith("EXTRACTED_SUFFIX")) {
//NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
dexfile = DexFile.loadDex(path, path + ".tmp", 0);
} else {
dexfile = new DexFile(path);
}
Enumeration<String> dexEntries = dexfile.entries();
while (dexEntries.hasMoreElements()) {
String className = dexEntries.nextElement();
if (className.startsWith(packageName)) {
classNames.add(className);
try {
Class clazz = Class.forName(className);
Object obj = clazz.newInstance();
Field field03 = clazz.getDeclaredField("holder"); // 獲取屬性為id的字段
String value= (String) field03.get(obj);
String[] split = value.split(":");
if (split!=null&&split.length==2) {
mapHolder.put(split[0],split[1]);
}
Log.i("test-->",mapHolder.toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
} catch (Throwable ignore) {
Log.e("ARouter", "Scan map file in dex files made error.", ignore);
} finally {
if (null != dexfile) {
try {
dexfile.close();
} catch (Throwable ignore) {
}
}
parserCtl.countDown();
}
}
});
}
parserCtl.await();
return classNames;
}
private static List<String> getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException {
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);
List<String> sourcePaths = new ArrayList<>();
sourcePaths.add(applicationInfo.sourceDir); //add the default apk path
return sourcePaths;
}
}
總結(jié)
- ARouter使用指南
- ARouter攔截器
- SchemeFilte 實現(xiàn)外部html 跳轉(zhuǎn)Native穆趴,打通WEB&Native
- 了解 JavaPoet &AutoService 注解處理器 apt原理
- 寫出簡易版CRouter未妹,通過實戰(zhàn)我們了解ARouter實現(xiàn)原理
- 項目demo地址
問題
- 除了ARouter络它,你知道利用apt 實現(xiàn)的框架都有哪些化戳?
- ARouter有沒有什么缺點?