上篇文章我們分析了ARouter的路由跳轉,這篇文章我們來分析interceptor攔截器。
首先,同樣在IDE編譯過程中,攔截器也會產生相應的檔案。(詳見ARouter源碼解析01-編譯組建檔案)
public class ARouter$$Interceptors$$app implements IInterceptorGroup { @Override public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) { interceptors.put(3, Test2Interceptor.class); interceptors.put(5, Test3Interceptor.class); interceptors.put(7, Test1Interceptor.class); }}
可以看到,這雷根據priority將Intercepter按照層級進行排序,層級從高到第依次put到interceptors集合中。那麼,這些intercepter是在什麼地方載入到記憶體中的呢。
同時,我們知道,攔截器有個init()方法,會在程式初始化的時候,進行調用,那麼,是在哪裡執行攔截器的init()方法的呢。
再回到ARouter.init()來看
public static void init(Application application) {//...hasInit = _ARouter.init(application);if (hasInit) { _ARouter.afterInit();}//...
}
這裡有個afterInit方法,我們跟進去看下
static void afterInit() { // Trigger interceptor init, use byName. interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();}
這裡,通過路由跳轉,調用了InterceptorServiceImpl,但是在路由app模組build檔案中,並沒有/arouter/service/interceptor這個路由表單,那麼ARouter這裡是通過怎麼跳轉的呢。
原來,在aroute-api中,還有個arouter的build檔案,在這個檔案下,有著和app模組下build包名相同的ARouter開頭的幾個檔案(故ARouter.init的時候,也會把這幾個路由表單載入進去)
package com.alibaba.android.arouter.routes;public class ARouter$$Group$$arouter implements IRouteGroup { @Override public void loadInto(Map<String, RouteMeta> atlas) { atlas.put("/arouter/service/autowired", RouteMeta.build(RouteType.PROVIDER, AutowiredServiceImpl.class, "/arouter/service/autowired", "arouter", null, -1, -2147483648)); atlas.put("/arouter/service/interceptor", RouteMeta.build(RouteType.PROVIDER, InterceptorServiceImpl.class, "/arouter/service/interceptor", "arouter", null, -1, -2147483648)); }}
我們再來在InterceptorServiceImpl,首先會在navigation的時候調用 LogisticsCenter.completion從而調用provider.init()方法進行初始化。
@Overridepublic void init(final Context context) { LogisticsCenter.executor.execute(new Runnable() { @Override public void run() { if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) { for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) { Class<? extends IInterceptor> interceptorClass = entry.getValue(); try { IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance(); iInterceptor.init(context); Warehouse.interceptors.add(iInterceptor); } catch (Exception ex) { throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]"); } } interceptorHasInit = true; synchronized (interceptorInitLock) { interceptorInitLock.notifyAll(); } } } });}
可以發現,大體的,就是通過線程池.execute(),在非同步線程中,擷取所有的攔截器IInterceptor,調用他們的init方法,並把攔截器添加到Warehouse.interceptors集合中。
知道了
接著,繼續在navigation方法中,如果沒有把postcard.isGreenChannel設為true,那麼調用interceptorService.doInterceptions執行攔截器,處理是否攔截。
完成了攔截器的init(),再來看navigation的時候,攔截器的攔截,
final class _ARouter { protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) { LogisticsCenter.completion(postcard); //isGreenChannel為ture,說明不需要interceptor,要跳過interceptor if (!postcard.isGreenChannel()) { interceptorService.doInterceptions(postcard, new InterceptorCallback() { @Override public void onContinue(Postcard postcard) { _navigation(context, postcard, requestCode, callback); } @Override public void onInterrupt(Throwable exception) { if (null != callback) { callback.onInterrupt(postcard); } } }); } else { return _navigation(context, postcard, requestCode, callback); } return null; }}
來看doInterceptions(),這裡進行攔截器的攔截,會遍曆攔截器列表,並調用攔截器的process(),最終,根據結果回調onContinue或onInterrupt來繼續navigation或終止navigation。
@Overridepublic void doInterceptions(final Postcard postcard, final InterceptorCallback callback) { // 檢查攔截器列表是否為空白 if (CollectionUtils.isNotEmpty(Warehouse.interceptors)) { // 等待攔截器服務完成初始化 // ...... LogisticsCenter.executor.execute(new Runnable() { @Override public void run() { // CountDown倒數計數器 CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size()); try { // 在另一個線程中遞迴依次執行攔截器操作 _excute(0, interceptorCounter, postcard); // 等待逾時 interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS); // 倒數計時器不為0,表示還有攔截器未執行完成 if (interceptorCounter.getCount() > 0) { // Cancel the navigation this time, if it hasn't return anythings. callback.onInterrupt(new HandlerException("The interceptor processing timed out.")); } else if (null != postcard.getTag()) { // Maybe some exception in the tag. callback.onInterrupt(new HandlerException(postcard.getTag().toString())); } else { callback.onContinue(postcard); } } catch (Exception e) { callback.onInterrupt(e); } } }); } else { callback.onContinue(postcard); }}/** * Excute interceptor * * @param index current interceptor index * @param counter interceptor counter * @param postcard routeMeta */private static void _excute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) { if (index < Warehouse.interceptors.size()) { IInterceptor iInterceptor = Warehouse.interceptors.get(index); iInterceptor.process(postcard, new InterceptorCallback() { @Override public void onContinue(Postcard postcard) { // Last interceptor excute over with no exception. counter.countDown(); _excute(index + 1, counter, postcard); // When counter is down, it will be execute continue ,but index bigger than interceptors size, then U know. } @Override public void onInterrupt(Throwable exception) { // Last interceptor excute over with fatal exception. postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage()); // save the exception message for backup. counter.cancel(); } }); }}
至此,即完成了interceptor的攔截,下篇文章,我們來解析ARouter的自動注入參數的功能。