服務(wù)管理
依賴注入
通過依賴注入的方式我們可以像上一篇文章中獲取跳轉(zhuǎn)參數(shù)一樣獲取服務(wù)赚导,具體的實(shí)現(xiàn)我們還是通過源碼來看一下吧。
當(dāng)我們隊(duì)一個(gè)自定義的service標(biāo)注上@Autowired注解的時(shí)候熄攘,重新編譯以后,APT會(huì)為我們自動(dòng)生成如下代碼:
至于inject方法在哪被調(diào)用上一篇文章已經(jīng)分析過了,這里可以看到服務(wù)的注入跟參數(shù)的注入還是有區(qū)別的,具體的實(shí)現(xiàn)是插件幫我們做了早直,我節(jié)選了一點(diǎn)代碼添上如下:
注意我圈出來的代碼,這里區(qū)分了服務(wù)和普通類型分別生成不同的代碼市框。而服務(wù)內(nèi)部注入的實(shí)例還是通過普通方式獲取的,也就是我下面要分析的第二種獲取服務(wù)的方式糕韧。
普通方式
普通方式也分為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中:
好了,實(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)明白了吧厚者。
攔截器
我們?cè)趯?shí)現(xiàn)攔截器的時(shí)候需要實(shí)現(xiàn)IInterceptor躁劣,而IInterceptor也實(shí)現(xiàn)了IProvider,所以IInterceptor也是一個(gè)服務(wù)库菲。所以interceptor的實(shí)例獲取方式也是跟普通的service是一樣的账忘,這里不做分析。
對(duì)應(yīng)上文的普通服務(wù)蝙昙。
下面讓我們來找一下具體得到攔截邏輯是在哪實(shí)現(xiàn)的呢闪萄?請(qǐng)看下面的代碼:
InterceptorServiceImpl#_excute
InterceptorServiceImpl屬于arouter核心服務(wù)類
InterceptorServiceImpl#doInterceptions
_ARouter#navigation
到這又回到我們上一篇文章頁(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)行指定竭缝。
到此,攔截器的實(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í)
如下代碼所示:
主要回調(diào)的就是onLost砚哆,那它又是在什么時(shí)候才被調(diào)用的呢?我們看如下代碼
它在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等