ARouter解析一:基本使用及頁面注冊源碼解析

ARouter是阿里2017年開源的頁面路由框架,是今年比較火的一個(gè)開源框架典鸡,目前在Github上已經(jīng)有2.2k的小星星了。官方對這個(gè)框架的定義是ARouter是阿里巴巴開源的Android平臺中對頁面、服務(wù)提供路由功能的中間件净当,提倡的是簡單且夠用翎迁。為了跟上潮流栋猖,我也打算來學(xué)習(xí)下這個(gè)開源框架,整個(gè)預(yù)計(jì)會(huì)分成四五個(gè)系列汪榔。今天我們先來看下基本使用和頁面注冊的源碼掂铐。

Google提供的原聲路由主要是通過intent,可以分成顯示和隱式兩種揍异。顯示的方案會(huì)導(dǎo)致類之間的直接依賴問題全陨,耦合嚴(yán)重;隱式intent需要的配置清單中統(tǒng)一聲明衷掷,首先有個(gè)暴露的問題辱姨,另外在多模塊開發(fā)中協(xié)作也比較困難。只要調(diào)用startActivity后面的環(huán)節(jié)我們就無法控制了戚嗅,在出現(xiàn)錯(cuò)誤時(shí)無能為力雨涛,而ARouter可以在跳轉(zhuǎn)過程中進(jìn)行攔截,出現(xiàn)錯(cuò)誤時(shí)可以實(shí)現(xiàn)降級策略懦胞,這個(gè)我們今天就不涉及到替久,后面我們會(huì)專門講。今天的分享會(huì)從下面幾個(gè)方面躏尉。

  • ARouter配置
  • activity頁面之間跳轉(zhuǎn)
  • APT技術(shù)
  • SPI技術(shù)
  • 頁面注冊源碼解析

我們就不直接擼demo了蚯根,直接使用官方的demo進(jìn)行分享。


demo.png

1.ARouter配置

配置之前我們先看下官方宣稱的ARouter的優(yōu)勢:

  • 直接解析URL路由胀糜,解析參數(shù)并賦值
  • 支持多模塊項(xiàng)目
  • 支持InstantRun
  • 允許自定義攔截器
  • ARouter可以提供IoC容器
  • 映射關(guān)系自動(dòng)注冊
  • 靈活的降級策略
    簡單講颅拦,就是很牛X,幾乎包含頁面跳轉(zhuǎn)的所需要的所有功能教藻。

在使用之前需要先配置gradle距帅,目前api最新的版本是1.2.1.1,處理器的最新版本是1.1.2.1.

android {
    defaultConfig {
    ...
    javaCompileOptions {
        annotationProcessorOptions {
        arguments = [ moduleName : project.getName() ]
        }
    }
    }
}

dependencies {
    // 替換成最新版本, 需要注意的是api
    // 要與compiler匹配使用括堤,均使用最新版可以保證兼容
    compile 'com.alibaba:arouter-api:1.2.1.1'
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.2.1'
    ...
}

接著需要盡早的初始化ARouter碌秸,可以考慮在Application中進(jìn)行初始化:

ARouter.init(mApplication); // 盡可能早绍移,推薦在Application中初始化

初始化工作就是這樣,接著我們看下頁面跳轉(zhuǎn)怎么玩讥电。

2.頁面跳轉(zhuǎn)使用

首先需要在支持路由的頁面上添加注解登夫,路徑path至少需要有兩級,比如我們需要跳轉(zhuǎn)到Test2Activity,那么需要在activity上面配置path,具體內(nèi)容不一定是/test/activity2允趟,可以自由發(fā)揮恼策。

@Route(path = "/test/activity2")
public class Test2Activity extends AppCompatActivity

然后直接像下面這樣就行了,build中的參數(shù)就是上面配置的路徑潮剪。

ARouter.getInstance().build("/test/activity2").navigation();

很簡單有木有涣楷?


activity跳轉(zhuǎn).png

如果需要跳轉(zhuǎn)的時(shí)候攜帶參數(shù)呢?

ARouter.getInstance().build("/test/activity2").withString("key1", "value1")
.navigation();

是不是so easy?ARouter提供了很多的withXX方法抗碰,可以攜帶基本類型,Object,Parcelable等等狮斗,里面的原理也是通過Bundle進(jìn)行攜帶mBundle.putXX

activity跳轉(zhuǎn)帶參數(shù).png

如果希望實(shí)現(xiàn)類似startActivityForResult呢?只需要在navigation中傳入兩個(gè)參數(shù)弧蝇,第一個(gè)就是Context碳褒,第二個(gè)參數(shù)是requestCode。

ARouter.getInstance().build("/test/activity2")
                     .withString("key1", "value1")
                     .navigation(this, 999);

在Test2Activity中就可以傳遞結(jié)果:

setResult(int resultCode)
或者
setResult(int resultCode, Intent data)

這里為了偷懶我們只是setResult(100);
然后我們就可以在onActivityResult中得到數(shù)據(jù),根據(jù)requestCode可以拿到數(shù)據(jù)看疗,我們這里只是彈個(gè)Toast沙峻。

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case 999:
                Toast.makeText(this, "get  resultCode:" + String.valueOf(resultCode), Toast.LENGTH_LONG).show();
            default:
                break;
        }
}
activtyForResult.png

基本跳轉(zhuǎn)就是上面幾種情況,接下來我們來看看源碼是怎么實(shí)現(xiàn)的两芳。

3.APT技術(shù)

APT摔寨,就是Annotation Processing Tool 的簡稱,就是可以在代碼編譯期間對注解進(jìn)行處理怖辆,并且生成Java文件是复,減少手動(dòng)的代碼輸入。這里我們就不多做介紹竖螃,這個(gè)不太清楚的可以參考我之前的分享Android模塊開發(fā)之APT技術(shù)淑廊。

4.SPI技術(shù)

Java提供的SPI全名就是Service Provider Interface,其實(shí)就是為某個(gè)接口尋找服務(wù)的機(jī)制,有點(diǎn)類似IOC的思想特咆,將裝配的控制權(quán)移交給ServiceLoader季惩。SPI在平時(shí)我們用到的會(huì)比較少,但是在Android模塊開發(fā)中就會(huì)比較有用坚弱,不同的模塊可以基于接口編程蜀备,每個(gè)模塊有不同的實(shí)現(xiàn)service provider,然后通過SPI機(jī)制自動(dòng)注冊到一個(gè)配置文件中关摇,就可以實(shí)現(xiàn)在程序運(yùn)行時(shí)掃描加載同一接口的不同service provider荒叶。不太清楚的可以參考之前的分析Android模塊開發(fā)之SPI

5.頁面注冊源碼分析

分析源碼之前我們需要先了解下框架的整個(gè)架構(gòu)输虱,這里直接引用官方的一張圖片些楣。

  • 最基礎(chǔ)的就是Compiler這個(gè)SDK,主要是用來在編譯期間處理注解Router/Interceptor/Autowire三個(gè)注解,在編譯期間自動(dòng)注冊注解標(biāo)注的類愁茁,成員變量等蚕钦。
  • API的SDK是用戶在運(yùn)行期使用。Launcher這一層只有ARouter和_ ARouter, ARouter就是我們需要打交道的接口鹅很,這里使用了代理模式嘶居,實(shí)際ARouter是通過_ ARouter進(jìn)行工作。
  • 第二層也是綠色的促煮,用戶也是可以調(diào)用到邮屁,這里主要是提供接口,我們可以擴(kuò)展服務(wù)菠齿,比如攔截器服務(wù)佑吝,成員變量裝配服務(wù)等,Template主要是提供模版接口绳匀,這個(gè)SDK會(huì)在編譯期生成一些映射文件芋忿,而這些映射文件會(huì)按照Template組件中提供的模板來生成,這樣按照一定的規(guī)則和約束生成映射文件也方便Route在運(yùn)行的時(shí)候進(jìn)行讀取疾棵。
  • Ware House類似一個(gè)倉庫戈钢,主要存儲ARouter在運(yùn)行期間加載的一些配置文件以及映射關(guān)系。
  • Thread則是提供了線程池是尔,因?yàn)榇嬖诙鄠€(gè)攔截器的時(shí)候以及跳轉(zhuǎn)過程中都是需要異步執(zhí)行的逆趣。
  • 再下一層就是Logistics Center,從名字上翻譯就是物流中心嗜历,整個(gè)SDK的流轉(zhuǎn)以及內(nèi)部調(diào)用最終都會(huì)下沉到這一層宣渗。
ARouter架構(gòu).png

我們先看下三個(gè)主要的注解,這個(gè)我刪掉了很多梨州,有需要的可以自行參考源碼痕囱。可以看出來三個(gè)注解的有效期間都是編譯期間暴匠,關(guān)于注解不太清楚的可以參考我們之前的分享反射注解與動(dòng)態(tài)代理綜合使用

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Route {

    /**
     * Path of route
     */
    String path();
    ……
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Interceptor {
    /**
     * The priority of interceptor, ARouter will be excute them follow the priority.
     */
    int priority();

    /**
     * The name of interceptor, may be used to generate javadoc.
     */
    String name() default "Default";
}

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Autowired {

    // Mark param's name or service name.
    String name() default "";

    // If required, app will be crash when value is null.
    // Primitive type wont be check!
    boolean required() default false;

    // Description of the field
    String desc() default "No desc.";
}

其實(shí)小伙伴們也可以猜出來鞍恢,ARouter會(huì)在編譯的時(shí)候?qū)outer注解標(biāo)注的activity掃描出來,并且按照定義好的模版生成裝配關(guān)系的代碼每窖。這個(gè)其實(shí)就是APT技術(shù)帮掉,我先前已經(jīng)做好鋪墊,英明神武吧:)窒典。簡單說就是要自定義注解的處理器蟆炊,繼承自AbstractProcessor,需要自己實(shí)現(xiàn)process方法來處理注解瀑志,然后需要用到SPI技術(shù)來注冊我們自己定義的注解處理器涩搓,之后JVM就能在編譯期間通過serviceLoader來找到我們的注解處理器balabala污秆。這里篇幅限制我們就不展開反復(fù)說了,不清楚的同學(xué)自行參考上面的鏈接昧甘。
ARouter的process方法比較長良拼,我們就看下生成的文件放在哪里,包名就是public static final String PACKAGE_OF_GENERATE_FILE = "com.alibaba.android.arouter.routes";
那么文件名呢充边?還記得我們前面跳轉(zhuǎn)Test2Activity的path是什么嗎庸推?@Route(path = "/test/activity2")其中test就是group,所以我們文件名就是groupFileName = ARouter$$Group$$test

public static final String SEPARATOR = "$$";
public static final String PROJECT = "ARouter";
public static final String NAME_OF_GROUP = PROJECT + SEPARATOR + "Group" + SEPARATOR;
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
String groupFileName = NAME_OF_GROUP + groupName;
                JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                        TypeSpec.classBuilder(groupFileName)
                                .addJavadoc(WARNING_TIPS)
                                .addSuperinterface(ClassName.get(type_IRouteGroup))
                                .addModifiers(PUBLIC)
                                .addMethod(loadIntoMethodOfGroupBuilder.build())
                                .build()
                ).build().writeTo(mFiler);
}
activity裝配關(guān)系.png

那么我們來看看ARouter自動(dòng)生成的activity裝配關(guān)系是怎么樣的浇冰。

public class ARouter$$Group$$test implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test", new java.util.HashMap<String, Integer>(){{put("key1", 8); }}, -1, -2147483648));
  }
}

有一個(gè)需要注意的地方就是put("key1", 8)予弧,還記得我們上面參數(shù)跳轉(zhuǎn)應(yīng)該是withString("key1", "value1"), 為什么這里是8?其實(shí)在編譯的時(shí)候做了處理湖饱,8代表類型String掖蛤。

public enum TypeKind {
    // Base type
    BOOLEAN,
    BYTE,
    SHORT,
    INT,
    LONG,
    CHAR,
    FLOAT,
    DOUBLE,

    // Other type
    STRING,
    PARCELABLE,
    OBJECT;
}

頁面自動(dòng)注冊的源碼基本就是上面這些內(nèi)容,我們最后引用一張官方的圖片井厌。

首先通過注解處理器掃出被標(biāo)注的類文件蚓庭;然后按照不同種類的源文件進(jìn)行分類,不僅僅提供了跳轉(zhuǎn)功能仅仆,它也能夠?qū)崿F(xiàn)模塊之間的解耦器赞,其實(shí)ARouter中的所有組件都是自動(dòng)注冊的

在按照不同種類的源文件進(jìn)行分類完成之后,就能夠按照固定的命名格式生成映射文件墓拜,這部分完成之后就意味著編譯期的部分已經(jīng)結(jié)束了港柜;

而最后一步的初始化其實(shí)是發(fā)生在運(yùn)行期的,在運(yùn)行期只需要通過固定的包名來加載映射文件就可以了咳榜,這就是頁面自動(dòng)注冊的整個(gè)流程夏醉。

注解&注解處理器.png

6.總結(jié)

到這里相信小伙伴們對于ARouter頁面跳轉(zhuǎn)的基本使用已經(jīng)很熟悉了。我們也簡單分析了下頁面注冊的原理涌韩,ARouter可以通過注解自動(dòng)注冊并且在編譯期間生成映射關(guān)系畔柔,在運(yùn)行的時(shí)候就可以加載文件,通過path就可以順利跳轉(zhuǎn)到目標(biāo)頁面臣樱。

好了靶擦,今天車就開到這了。估計(jì)再說下去小伙伴們該睡覺了雇毫,關(guān)于加載配置文件和頁面跳轉(zhuǎn)我們就在解析二中分析玄捕,歡迎關(guān)注。

你們的贊是我最大的動(dòng)力棚放,謝謝枚粘!

關(guān)于注解和APT技術(shù)與SPI技術(shù)不太清楚的小伙伴可自行參考下面鏈接:
Android模塊開發(fā)之APT技術(shù)
Android模塊開發(fā)之SPI

歡迎關(guān)注公眾號:JueCode

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市席吴,隨后出現(xiàn)的幾起案子赌结,更是在濱河造成了極大的恐慌捞蛋,老刑警劉巖孝冒,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柬姚,死亡現(xiàn)場離奇詭異,居然都是意外死亡庄涡,警方通過查閱死者的電腦和手機(jī)量承,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穴店,“玉大人撕捍,你說我怎么就攤上這事∑矗” “怎么了忧风?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長球凰。 經(jīng)常有香客問我狮腿,道長,這世上最難降的妖魔是什么呕诉? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任缘厢,我火速辦了婚禮,結(jié)果婚禮上甩挫,老公的妹妹穿的比我還像新娘贴硫。我一直安慰自己,他們只是感情好伊者,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布英遭。 她就那樣靜靜地躺著,像睡著了一般亦渗。 火紅的嫁衣襯著肌膚如雪贪绘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天央碟,我揣著相機(jī)與錄音税灌,去河邊找鬼。 笑死亿虽,一個(gè)胖子當(dāng)著我的面吹牛菱涤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洛勉,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼粘秆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了收毫?” 一聲冷哼從身側(cè)響起攻走,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤殷勘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后昔搂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玲销,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年摘符,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贤斜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逛裤,死狀恐怖瘩绒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情带族,我是刑警寧澤锁荔,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站蝙砌,受9級特大地震影響阳堕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拍霜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一嘱丢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧祠饺,春花似錦越驻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至勺鸦,卻和暖如春并巍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背换途。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工懊渡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人军拟。 一個(gè)月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓剃执,卻偏偏與公主長得像,于是被迫代替她去往敵國和親懈息。 傳聞我的和親對象是個(gè)殘疾皇子肾档,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容