ARouter 源碼淺析第二篇

服務(wù)管理

依賴注入

通過依賴注入的方式我們可以像上一篇文章中獲取跳轉(zhuǎn)參數(shù)一樣獲取服務(wù)赚导,具體的實(shí)現(xiàn)我們還是通過源碼來看一下吧。
當(dāng)我們隊(duì)一個(gè)自定義的service標(biāo)注上@Autowired注解的時(shí)候熄攘,重新編譯以后,APT會(huì)為我們自動(dòng)生成如下代碼:


image.png

至于inject方法在哪被調(diào)用上一篇文章已經(jīng)分析過了,這里可以看到服務(wù)的注入跟參數(shù)的注入還是有區(qū)別的,具體的實(shí)現(xiàn)是插件幫我們做了早直,我節(jié)選了一點(diǎn)代碼添上如下:


image.png

注意我圈出來的代碼,這里區(qū)分了服務(wù)和普通類型分別生成不同的代碼市框。而服務(wù)內(nèi)部注入的實(shí)例還是通過普通方式獲取的,也就是我下面要分析的第二種獲取服務(wù)的方式糕韧。

普通方式

image.png

普通方式也分為2種枫振,一種是根據(jù)name,另一種就是根據(jù)type萤彩。
下面只分析第一種根據(jù)name來獲取服務(wù)的方式粪滤,因?yàn)楦鶕?jù)type來獲取實(shí)例是差不多的。

_ARouter#_navigation

private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        final Context currentContext = null == context ? mContext : context;

        switch (postcard.getType()) {
            case ACTIVITY:
                ……
                break;
            case PROVIDER:
                //注意這行代碼
                return postcard.getProvider();
            case BOARDCAST:
            case CONTENT_PROVIDER:
            case FRAGMENT:
                Class fragmentMeta = postcard.getDestination();
                try {
                    Object instance = fragmentMeta.getConstructor().newInstance();
                    if (instance instanceof Fragment) {
                        ((Fragment) instance).setArguments(postcard.getExtras());
                    } else if (instance instanceof android.support.v4.app.Fragment) {
                        ((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
                    }

                    return instance;
                } catch (Exception ex) {
                    logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
                }
            case METHOD:
            case SERVICE:
            default:
                return null;
        }

        return null;
    }

最后會(huì)根據(jù)postcard.getType()類型來匹配PROVIDER雀扶,然后返回provider實(shí)例杖小,而provider的set是在LogisticsCenter#completion中:

image.png

好了,實(shí)例獲取到了其他的也就沒什么好分析的了愚墓。
這里提醒一下予权,根據(jù)type來獲取實(shí)例有局限性,只支持全局只有一個(gè)實(shí)現(xiàn)了相應(yīng)接口的實(shí)現(xiàn)類浪册,否則獲取到的實(shí)例是系統(tǒng)掃描到的實(shí)現(xiàn)最后一個(gè)實(shí)例扫腺,同上一篇文章的PathReplaceService
why:那為什么根據(jù)type和根據(jù)那么來獲取實(shí)例會(huì)有區(qū)別呢村象?通過源碼我們發(fā)現(xiàn)type是從providersIndex Map中去獲取實(shí)例的笆环,而name是從providers Map中去獲取實(shí)例的。相信到這大家應(yīng)該已經(jīng)明白了吧厚者。
image.png

攔截器

我們?cè)趯?shí)現(xiàn)攔截器的時(shí)候需要實(shí)現(xiàn)IInterceptor躁劣,而IInterceptor也實(shí)現(xiàn)了IProvider,所以IInterceptor也是一個(gè)服務(wù)库菲。所以interceptor的實(shí)例獲取方式也是跟普通的service是一樣的账忘,這里不做分析。


image.png

對(duì)應(yīng)上文的普通服務(wù)蝙昙。
下面讓我們來找一下具體得到攔截邏輯是在哪實(shí)現(xiàn)的呢闪萄?請(qǐng)看下面的代碼:

InterceptorServiceImpl#_excute

InterceptorServiceImpl屬于arouter核心服務(wù)類


image.png

InterceptorServiceImpl#doInterceptions

image.png

_ARouter#navigation

image.png

到這又回到我們上一篇文章頁(yè)面跳轉(zhuǎn)主流程的邏輯,他其實(shí)就是在真正跳轉(zhuǎn)之前奇颠,先判斷有沒有符合的攔截器败去,有的話則先進(jìn)行攔截器里的操作。這里要注意一點(diǎn)的是:攔截器是有優(yōu)先級(jí)的烈拒,按照priority排序圆裕,priority越小優(yōu)先級(jí)越高广鳍。這是因?yàn)?br> interceptorsIndex的類型是TreeMap,他具有以下兩條特性:

1吓妆、TreeMap如不指定排序器赊时,默認(rèn)將按照key值進(jìn)行升序排序,如果指定了排序器行拢,則按照指定的排序器進(jìn)行排序祖秒。
2、具體的排序規(guī)則舟奠,開發(fā)人員可以在int compare()方法中進(jìn)行指定竭缝。

image.png

到此,攔截器的實(shí)現(xiàn)原理我們也就分析清楚了沼瘫。

降級(jí)策略

我們知道使用系統(tǒng)自帶的StartActivity()啟動(dòng)后就無(wú)法插手其中任何環(huán)節(jié)了抬纸,只能交給系統(tǒng)管理,這就導(dǎo)致了在跳轉(zhuǎn)失敗的情況下無(wú)法降級(jí)耿戚,而是會(huì)直接拋出運(yùn)營(yíng)級(jí)的異常湿故,甚至導(dǎo)致崩潰,這個(gè)給用戶的感覺就不是很好膜蛔。所以ARouter就為我們提供了降級(jí)策略坛猪,主要分為2中方式,單獨(dú)降級(jí)和全局降級(jí)(demo中這樣稱呼的)飞几。

單獨(dú)降級(jí)(接口回調(diào))&全局降級(jí)

如下代碼所示:


image.png

主要回調(diào)的就是onLost砚哆,那它又是在什么時(shí)候才被調(diào)用的呢?我們看如下代碼


image.png

它在completion中主動(dòng)拋出異常被捕獲時(shí)調(diào)用的屑墨,如果callback不為null就會(huì)被調(diào)用躁锁,由此也可以看出單獨(dú)降級(jí)的優(yōu)先級(jí)是高于全局降級(jí)的,else中的代碼就是全局降級(jí)的代碼卵史。使用方式也跟普通的服務(wù)是一樣的這里就不分析了战转。
我們?cè)倏纯碙ogisticsCenter.completion這個(gè)方法,這個(gè)是與編譯期間生成的映射文件直接打交道的模塊以躯。先在加載到內(nèi)存的節(jié)點(diǎn)倉(cāng)庫(kù)中查找是否有該目標(biāo)節(jié)點(diǎn)的存在槐秧,沒有就到組倉(cāng)庫(kù)中找,找不到就報(bào)錯(cuò)NoRouteFoundException忧设,這就到了我們上面的邏輯中刁标。

LogisticsCenter#completion

public synchronized static void completion(Postcard postcard) {
        if (null == postcard) {
            throw new NoRouteFoundException(TAG + "No postcard!");
        }

        RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
        if (null == routeMeta) {    // Maybe its does't exist, or didn't load.
            Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // Load route meta.
            if (null == groupMeta) {
                throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
            }
        }
}

總結(jié)

經(jīng)過兩篇文章,我們基本上已經(jīng)把ARouter的主要功能都分析了址晕。其實(shí)看著很神奇的功能膀懈,只要我們深入到源碼里就會(huì)發(fā)現(xiàn)其實(shí)也就那么回事。不過我們還是能從優(yōu)秀得到框架中學(xué)到很多優(yōu)秀的設(shè)計(jì)思想和前沿的技術(shù)的谨垃,比如IOC启搂、APT硼控, AOP等

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市胳赌,隨后出現(xiàn)的幾起案子牢撼,更是在濱河造成了極大的恐慌,老刑警劉巖疑苫,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熏版,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡缀匕,警方通過查閱死者的電腦和手機(jī)纳决,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乡小,“玉大人,你說我怎么就攤上這事饵史÷樱” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵胳喷,是天一觀的道長(zhǎng)湃番。 經(jīng)常有香客問我,道長(zhǎng)吭露,這世上最難降的妖魔是什么吠撮? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮讲竿,結(jié)果婚禮上泥兰,老公的妹妹穿的比我還像新娘。我一直安慰自己题禀,他們只是感情好鞋诗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著迈嘹,像睡著了一般削彬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秀仲,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天融痛,我揣著相機(jī)與錄音,去河邊找鬼神僵。 笑死雁刷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的挑豌。 我是一名探鬼主播安券,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼墩崩,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了侯勉?” 一聲冷哼從身側(cè)響起鹦筹,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎址貌,沒想到半個(gè)月后铐拐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡练对,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年遍蟋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片螟凭。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虚青,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出螺男,到底是詐尸還是另有隱情棒厘,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布下隧,位于F島的核電站奢人,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏淆院。R本人自食惡果不足惜何乎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望土辩。 院中可真熱鬧支救,春花似錦、人聲如沸脯燃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)辕棚。三九已至欲主,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逝嚎,已是汗流浹背扁瓢。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留补君,地道東北人引几。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親伟桅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子敞掘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,182評(píng)論 25 707
  • 幼兒園畢業(yè)是人生的第一個(gè)畢業(yè)季,也是即將踏入正式上學(xué)漫漫路的起點(diǎn): 孩子們楣铁,老師是呵護(hù)你三年而又將你放飛的鳥媽媽玖雁。...
    冬日私語(yǔ)閱讀 708評(píng)論 0 0
  • Uber drama fails to hurt its business, figures suggest (t...
    Eugenia_a970閱讀 608評(píng)論 0 0
  • 看《二十二》之前,我做了很多的心理建設(shè)盖腕。 小時(shí)候赫冬,看過一本《南京大屠殺》的連環(huán)畫,兩天沒吃下飯溃列,后來的電影也不敢看...
    大鳥8wo閱讀 430評(píng)論 1 3