ARouter源碼分析

組件化被越來(lái)越多的Android項(xiàng)目采用,而作為組件化的基礎(chǔ)——路由也是重中之重。本篇文章將詳細(xì)的分析阿里巴巴開(kāi)源的路由框架ARouter。從源碼的角度解釋為什么這樣使用,以及避免做什么,讓你使用地更加順滑。

項(xiàng)目地址

ARouter

項(xiàng)目結(jié)構(gòu)

我們把項(xiàng)目clone到本地,打開(kāi)ARouter項(xiàng)目,可以看到分為如下幾個(gè)Module:

image

其中app、module-java、module-kotlin是演示demo相關(guān)的,也就是使用的示例。

arouter-register是1.3.0版本新添加的gradle插件的代碼,用于路由表的自動(dòng)注冊(cè),可以縮短初始化時(shí)間,解決應(yīng)用加固導(dǎo)致無(wú)法直接訪(fǎng)問(wèn)dex文件初始化失敗的問(wèn)題。(本篇文章不涉及這個(gè)模塊)

arouter-annotation包含了注解類(lèi)以及攜帶數(shù)據(jù)的bean;

arouter-compiler包含了注解處理類(lèi),通過(guò)java的Annotation Processor Tool按照定義的Processor生成所需要的類(lèi)。
以demo為例子,當(dāng)運(yùn)行項(xiàng)目后會(huì)在build文件下生成arouter相關(guān)的代碼:

image

我們先不用去關(guān)心生成代碼的細(xì)節(jié),只需要知道按照用法的提示添加諸如Route等注解之后,arouter-compiler中的注解處理類(lèi)會(huì)自動(dòng)幫我們生成需要的代碼(如上圖所示)。對(duì)源碼的分析也只需要知道生成的類(lèi)的做了什么就夠了。

本篇文章也不討論生成代碼細(xì)節(jié),如果想了解apt的生成過(guò)程,可以參考:Java注解處理器 以及更方便生成的Java代碼的庫(kù)javapoet。

arouter-api提供了給我們使用的api,以實(shí)現(xiàn)路由功能。

那我們就從api開(kāi)始分析。

源碼分析

init

按照官方說(shuō)明,我們找到Arouter的入口,也就是初始化的地方:

if (isDebug()) {           // 這兩行必須寫(xiě)在init之前,否則這些配置在init過(guò)程中將無(wú)效
    ARouter.openLog();     // 打印日志
    ARouter.openDebug();   // 開(kāi)啟調(diào)試模式(如果在InstantRun模式下運(yùn)行,必須開(kāi)啟調(diào)試模式!線(xiàn)上版本需要關(guān)閉,否則有安全風(fēng)險(xiǎn))
}
ARouter.init(mApplication); // 盡可能早,推薦在A(yíng)pplication中初始化

我們直接進(jìn)入ARouter.init方法:

    /**
     * Init, it must be call before used router.
     */
    public static void init(Application application) {
        if (!hasInit) { //確保只初始化一次
            logger = _ARouter.logger;//日志類(lèi)
            _ARouter.logger.info(Consts.TAG, "ARouter init start.");
            hasInit = _ARouter.init(application);

            if (hasInit) {
                _ARouter.afterInit();
            }

            _ARouter.logger.info(Consts.TAG, "ARouter init over.");
        }
    }

變量hasInit用于保證初始化代碼只執(zhí)行一次;
logger是一個(gè)日志工具類(lèi);

注意_ARouter類(lèi)的下劃線(xiàn),Arouter是對(duì)外暴露api的類(lèi),而_ARouter是真正的實(shí)現(xiàn)類(lèi)。為什么這樣設(shè)計(jì)那?當(dāng)然是為了解耦啦。具體點(diǎn)說(shuō)有哪些好處呢?看看這個(gè)init方法,除了對(duì)實(shí)現(xiàn)類(lèi)的調(diào)用,還有日志的打印,有沒(méi)有裝飾模式的感覺(jué)?可以增加一些額外的功能。其次,對(duì)比_ARouter類(lèi)與Arouter類(lèi)的方法,可以看到明顯Arouter類(lèi)的方法少。要知道Arouter是對(duì)外暴露的,我們可以有選擇暴露用戶(hù)需要的方法,而把一些方法隱藏在內(nèi)部。相比于用private修飾,這種方式靈活性更強(qiáng)。

接著我們進(jìn)入實(shí)現(xiàn)類(lèi)看下:

protected static synchronized boolean init(Application application) {
        mContext = application;
        LogisticsCenter.init(mContext, executor);
        logger.info(Consts.TAG, "ARouter init success!");
        hasInit = true;
        return true;
    }

明顯有價(jià)值的是LogisticsCenter.init(mContext, executor);,executor是一個(gè)線(xiàn)程池。我們接著來(lái)看下去除日志等無(wú)關(guān)代碼后的LogisticsCenter.init方法:

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
    mContext = context;
    executor = tpe;
    ...

    Set<String> routerMap;//生成類(lèi)的類(lèi)名集合
    // 如果是debug模式或者是新版本,從apt生成的包中加載類(lèi)
    if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
        routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
        if (!routerMap.isEmpty()) {//加入sp緩存
            context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
        }

        PackageUtils.updateVersion(context); //更新版本
    } else {//否則從緩存讀取類(lèi)名
        routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
    }

    //判斷類(lèi)型,使用反射實(shí)例化對(duì)象,并調(diào)用方法
    for (String className : routerMap) {
        if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
            ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
            ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
            ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
        }
    }
    ...
}

這里體現(xiàn)了debuggable模式的作用,如果沒(méi)有開(kāi)啟debuggable,并且調(diào)試的時(shí)候肯定不會(huì)更改版本號(hào),因此只會(huì)從緩存中讀取類(lèi)信息,所以新添加的路由不會(huì)加載到內(nèi)存中。

ROUTE_ROOT_PAKCAGE是一個(gè)常量:

public static final String ROUTE_ROOT_PAKCAGE = "com.alibaba.android.arouter.routes";

可以看到與上面demo生成類(lèi)的截圖的包名相同。而ClassUtils.getFileNameByPackageName方法做的就是找到app的dex,然后遍歷出其中的屬于com.alibaba.android.arouter.routes包下的所有類(lèi)名,打包成集合返回??梢韵胂蟊闅v整個(gè)dex查找指定類(lèi)名的工作量有多大,因此才會(huì)有開(kāi)頭提到的1.3.0版本新增gradle插件來(lái)代替這個(gè)過(guò)程。

拿到所有生成類(lèi)名的集合后,通過(guò)反射實(shí)例化對(duì)象并調(diào)用方法,將注解的一些元素添加到static集合中:

class Warehouse {
    // Cache route and metas
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    static Map<String, RouteMeta> routes = new HashMap<>();

    // Cache provider
    static Map<Class, IProvider> providers = new HashMap<>();
    static Map<String, RouteMeta> providersIndex = new HashMap<>();

    // Cache interceptor
    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
    static List<IInterceptor> interceptors = new ArrayList<>();
}

interceptor的map有些特別,是UniqueKeyTreeMap,其實(shí)做的很簡(jiǎn)單,僅僅是在key(優(yōu)先級(jí))相同時(shí),拋出指定的異常。因此,記住不要出現(xiàn)優(yōu)先級(jí)相同的interceptor。

生成的類(lèi)有統(tǒng)一的命名規(guī)則,方便區(qū)分,分別實(shí)現(xiàn)對(duì)應(yīng)的接口:

public interface IRouteRoot {
    void loadInto(Map<String, Class<? extends IRouteGroup>> routes);
}

public interface IInterceptorGroup {
    void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptor);
}

public interface IProviderGroup {
    void loadInto(Map<String, RouteMeta> providers);
}

public interface IRouteGroup {
    void loadInto(Map<String, RouteMeta> atlas);
}

我們來(lái)看下demo生成的實(shí)現(xiàn)類(lèi)都做了什么:

public class ARouter$Root$app implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    //key為分組名,即路徑的第一段,value為分組中所有的映射關(guān)系
    routes.put("service", ARouter$Group$service.class);
    routes.put("test", ARouter$Group$test.class);
  }
}

//將module中使用@Route注解的activity或Fragment添加到集合中,這里的方法會(huì)在之后調(diào)用
public class ARouter$Group$test implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test", new java.util.HashMap<String, Integer>(){{put("pac", 9); put("ch", 5); put("fl", 6); put("obj", 10); put("name", 8); put("dou", 7); put("boy", 0); put("objList", 10); put("map", 10); put("age", 3); put("url", 8); put("height", 3); }}, -1, -2147483648));
    atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test", new java.util.HashMap<String, Integer>(){{put("key1", 8); }}, -1, -2147483648));
    atlas.put("/test/activity3", RouteMeta.build(RouteType.ACTIVITY, Test3Activity.class, "/test/activity3", "test", new java.util.HashMap<String, Integer>(){{put("name", 8); put("boy", 0); put("age", 3); }}, -1, -2147483648));
    atlas.put("/test/activity4", RouteMeta.build(RouteType.ACTIVITY, Test4Activity.class, "/test/activity4", "test", null, -1, -2147483648));
    atlas.put("/test/fragment", RouteMeta.build(RouteType.FRAGMENT, BlankFragment.class, "/test/fragment", "test", null, -1, -2147483648));
    atlas.put("/test/webview", RouteMeta.build(RouteType.ACTIVITY, TestWebview.class, "/test/webview", "test", null, -1, -2147483648));
  }
}

IRouteRoot的實(shí)現(xiàn)將有@Route注解的module名添加到參數(shù)集合中,也就是groupsIndex。

這里會(huì)存在一個(gè)小陷阱,如果不同的module中存在相同的分組(即路徑的第一段,如上面的“test”),則會(huì)在對(duì)應(yīng)的module中生成不同的IRouteGroup的實(shí)現(xiàn),然后在此處會(huì)執(zhí)行分別執(zhí)行routes.put("test", ARouter$Group$moduleA.class);,以及routes.put("test", ARouter$Group$moduleB.class);,但是因?yàn)閗ey相同,因此前一個(gè)會(huì)被覆蓋,導(dǎo)致前一個(gè)定義的路由無(wú)法找到。具體可以看我提的issue,官方的建議是路徑分組與模塊名相同,并且不同模塊不要使用相同的分組。

public class ARouter$Interceptors$app implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    //key是優(yōu)先級(jí)
    interceptors.put(7, Test1Interceptor.class);
  }
}

同樣的IInterceptorGroup的實(shí)現(xiàn)將@Interceptor注解的類(lèi)添加到參數(shù)集合中,也就是interceptorsIndex中。

public class ARouter$Providers$app implements IProviderGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> providers) {
    providers.put("com.alibaba.android.arouter.demo.testservice.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/service/hello", "service", null, -1, -2147483648));
    providers.put("com.alibaba.android.arouter.facade.service.SerializationService", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/service/json", "service", null, -1, -2147483648));
    providers.put("com.alibaba.android.arouter.demo.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/service/single", "service", null, -1, -2147483648));
  }
}

IProviderGroup的實(shí)現(xiàn)將繼承自IProvider的類(lèi)添加到參數(shù)集合中,也就是providersIndex中。

RouteMeta是一個(gè)數(shù)據(jù)bean,封裝了被注解類(lèi)的一些信息

public class RouteMeta {
    private RouteType type;         // Type of route
    private Element rawType;        // Raw type of route
    private Class<?> destination;   // Destination
    private String path;            // Path of route
    private String group;           // Group of route
    private int priority = -1;      // The smaller the number, the higher the priority
    private int extra;              // Extra data
    private Map<String, Integer> paramsType;  // Param type

    public static RouteMeta build(RouteType type, Class<?> destination, String path, String group, Map<String, Integer> paramsType, int priority, int extra) {
        return new RouteMeta(type, null, destination, path, group, paramsType, priority, extra);
    }
    ...
}

其中paramsType是包含了所有注解了Autowired的屬性的信息,key為屬性名,value為屬性類(lèi)型,ARouter將可被intent傳遞的數(shù)據(jù)類(lèi)型定義了對(duì)應(yīng)的int類(lèi)型: BOOLEAN,BYTE,SHORT,INT,LONG,CHAR,FLOAT,DOUBLE,STRING,PARCELABLE,OBJECT分別對(duì)應(yīng)0,1,2,3...

RouteType是一個(gè)枚舉,表示被注解類(lèi)的路由類(lèi)型:

public enum RouteType {
    ACTIVITY(0, "android.app.Activity"),
    SERVICE(1, "android.app.Service"),
    PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider"),
    CONTENT_PROVIDER(-1, "android.app.ContentProvider"),
    BOARDCAST(-1, ""),
    METHOD(-1, ""),
    FRAGMENT(-1, "android.app.Fragment"),
    UNKNOWN(-1, "Unknown route type");

    int id;
    String className;

    RouteType(int id, String className) {
        this.id = id;
        this.className = className;
    }

    ...
}

可以看到ARouter雖然目前只支持Activity和Fragment,但是也預(yù)留了Service和Boardcast的類(lèi)型,可能以后也會(huì)實(shí)現(xiàn)。

最后別忘了init中還有一個(gè)_ARouter.afterInit();方法:

static void afterInit() {
    // Trigger interceptor init, use byName.
    interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}

它是一個(gè)管理攔截器的服務(wù),實(shí)現(xiàn)了IProvider接口,并且用自己實(shí)現(xiàn)的的路由方式獲取實(shí)例。嗯,沒(méi)毛??!

根據(jù)官方的說(shuō)明,IProvider接口是用來(lái)暴露服務(wù),并且在初始化的時(shí)候會(huì)被調(diào)用init(Context context)方法。具體的服務(wù)有其實(shí)現(xiàn)提供,那我們就來(lái)看下它的實(shí)現(xiàn)做了些什么:

@Route(path = "/arouter/service/interceptor")
public class InterceptorServiceImpl implements InterceptorService {
    private static boolean interceptorHasInit;
    private static final Object interceptorInitLock = new Object();

    @Override
    public void init(final Context context) {
       ... //省略子線(xiàn)程以及同步處理,下面的操作實(shí)際是在子線(xiàn)程處理的
        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() + "]");
                }
            }
        ...
    }
}

還記的在上一步初始化的時(shí)候?qū)⑺凶⒔饬薎nterceptor的類(lèi)的信息存入了Warehouse.interceptorsIndex,這里就將這些類(lèi)實(shí)例化,并調(diào)用iInterceptor.init(context);完成自定義的初始化內(nèi)容,最后放入Warehouse.interceptors集合中。

總結(jié)來(lái)說(shuō),init過(guò)程就是把所有注解的信息加載內(nèi)存中,并且完成所有攔截器的初始化。

navigation

完成初始化之后,就可以實(shí)現(xiàn)路由跳轉(zhuǎn)了:

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

那我們就從這里開(kāi)始分析:
getInstance()是獲取ARouter類(lèi)的單例方法,沒(méi)什么好說(shuō)的。

public Postcard build(String path) {
    return _ARouter.getInstance().build(path);
}

build方法調(diào)動(dòng)了實(shí)現(xiàn)類(lèi)_ARouter的build方法,繼續(xù)看:

protected Postcard build(String path) {
    ...//省略判空
    PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
    if (null != pService) {
        path = pService.forString(path);
    }
    return build(path, extractGroup(path));
}

protected Postcard build(String path, String group) {
    if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
        throw new HandlerException(Consts.TAG + "Parameter is invalid!");
    } else {
        PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
        if (null != pService) {
            path = pService.forString(path);
        }
        return new Postcard(path, group);
    }
}

這里出現(xiàn)一個(gè)PathReplaceService,它是繼承IProvider的接口,它是預(yù)留給用戶(hù)實(shí)現(xiàn)路徑動(dòng)態(tài)變化功能,官方有詳細(xì)說(shuō)明:

public interface PathReplaceService extends IProvider {
    String forString(String path);
    Uri forUri(Uri uri);
}

需要注意的是,build(String path)方法及build(String path, String group)方法中都嘗試使用PathReplaceService完成路徑動(dòng)態(tài)變化,因此,在變化前需要做好判斷,否則出現(xiàn)變換兩次的情況(例如拼接字符)。

extractGroup方法截取路徑中的第一段作為分組名。

build方法最終返回一個(gè)Postcard對(duì)象。它也是一個(gè)數(shù)據(jù)bean,繼承自RouteMeta,附加一些跳轉(zhuǎn)信息,如參數(shù)之類(lèi):

public final class Postcard extends RouteMeta {
    // Base
    private Uri uri;
    private Object tag;             // A tag prepare for some thing wrong.
    private Bundle mBundle;         // Data to transform
    private int flags = -1;         // Flags of route
    private int timeout = 300;      // Navigation timeout, TimeUnit.Second
    private IProvider provider;     // It will be set value, if this postcard was provider.
    private boolean greenChannel;
    private SerializationService serializationService;

    // Animation
    private Bundle optionsCompat;    // The transition animation of activity
    private int enterAnim = -1;
    private int exitAnim = -1;

    ...
}

最后調(diào)用該P(yáng)ostcard對(duì)象的navigation方法,層層調(diào)用,最終還是調(diào)用的_Arouter的navigation方法,我們先來(lái)看下方法的前半部分:

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    try {
        LogisticsCenter.completion(postcard);
    } catch (NoRouteFoundException ex) {
        if (null != callback) {
            callback.onLost(postcard);
        } else {    // 交給全局降級(jí)策略
            DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
            if (null != degradeService) {
                degradeService.onLost(context, postcard);
            }
        }
        return null;
    }

    if (null != callback) {
        callback.onFound(postcard);
    }

    ...    //方法未結(jié)束,分到之后
}

大致可看出LogisticsCenter.completion(postcard);肯定是試圖找到跳轉(zhuǎn)的目標(biāo),如果找不到則讓callback回調(diào)onLost,或者交給全局降級(jí)策略處理。找到則回調(diào)callback的onFound方法。

那我們看看LogisticsCenter.completion(postcard);是如何尋找的:

public synchronized static void completion(Postcard postcard) {
    ...
    //從集合中找路徑對(duì)應(yīng)的RouteMeta
    RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
    if (null == routeMeta) {    // 內(nèi)存中沒(méi)有,可能是還沒(méi)有加載過(guò)
        Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // 找到分組
        if (null == groupMeta) {//分組也沒(méi)有,那就是沒(méi)有注冊(cè)
            throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
        } else { // 加載具體分組的映射,并從groupsIndex集合中刪除類(lèi)信息
            try {
                IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                iGroupInstance.loadInto(Warehouse.routes);
                Warehouse.groupsIndex.remove(postcard.getGroup());
            } catch (Exception e) {
                throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
            }
            completion(postcard);   // 遞歸再次嘗試加載
        }
    } else { 
        //拷貝數(shù)據(jù)
        postcard.setDestination(routeMeta.getDestination());
        postcard.setType(routeMeta.getType());
        postcard.setPriority(routeMeta.getPriority());
        postcard.setExtra(routeMeta.getExtra());

        Uri rawUri = postcard.getUri();
        if (null != rawUri) {   // 如果是Uri跳轉(zhuǎn)
            Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);//分割路徑中的參數(shù)
            Map<String, Integer> paramsType = routeMeta.getParamsType();//獲取Autowired注解的屬性
            if (MapUtils.isNotEmpty(paramsType)) { //將屬性對(duì)應(yīng)的參數(shù)值放入Bundle
                for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
                    setValue(postcard,
                            params.getValue(),
                            params.getKey(),
                            resultMap.get(params.getKey()));
                }

                // Bundle存入需要自動(dòng)注入的屬性信息
                postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
            }

            // 保存原始路徑
            postcard.withString(ARouter.RAW_URI, rawUri.toString());
        }

        switch (routeMeta.getType()) {
            case PROVIDER:  //如果目標(biāo)類(lèi)型是provider,實(shí)例化對(duì)象并放入postcard
                Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                IProvider instance = Warehouse.providers.get(providerMeta);
                if (null == instance) { 
                    IProvider provider;
                    try {
                        provider = providerMeta.getConstructor().newInstance();
                        provider.init(mContext);//初始化在這里調(diào)用
                        Warehouse.providers.put(providerMeta, provider);
                        instance = provider;
                    } catch (Exception e) {
                        throw new HandlerException("Init provider failed! " + e.getMessage());
                    }
                }
                postcard.setProvider(instance);
                postcard.greenChannel();    // Provider不經(jīng)過(guò)攔截器處理
                break;
            case FRAGMENT:
                postcard.greenChannel();    // Fragment不僅過(guò)攔截器處理
            default:
                break;
        }
    }
}

可以看到主要功能是找到匹配的目標(biāo)類(lèi),并將目標(biāo)類(lèi)的一些信息拷貝到postcard對(duì)象中。

我們繼續(xù)看navigation方法的后半部分:

protected Object navigation(final Context context, final Postcard postcard, final int request

Code, final NavigationCallback callback) {
    ...
    if (!postcard.isGreenChannel()) {  //不是綠色通道,即經(jīng)過(guò)攔截器處理
        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;
}

_navigation方法是最終處理,并且有返回值,如果路由目標(biāo)是Fragment或者IProvider的話(huà)。攔截器的處理可能會(huì)耗時(shí),因此會(huì)放到子線(xiàn)程處理,通過(guò)回調(diào)完成繼續(xù)操作,但此時(shí)就無(wú)法返回目標(biāo)類(lèi)(Fragment或IProvider),也就解釋了為什么上面的completion方法中設(shè)置了綠色通道。

我們先不考慮攔截過(guò)程,直接看_navigation方法:

private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    //mContext是init傳入的Application
    final Context currentContext = null == context ? mContext : context;

    switch (postcard.getType()) {
        case ACTIVITY:
            // Build intent
            final Intent intent = new Intent(currentContext, postcard.getDestination());
            intent.putExtras(postcard.getExtras());

            // Set flags.
            int flags = postcard.getFlags();
            if (-1 != flags) {
                intent.setFlags(flags);
            } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }

            //攔截過(guò)程在子線(xiàn)程,因此該方法可能仍在子線(xiàn)程,需要切換到主線(xiàn)程
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    if (requestCode > 0) {  // Need start for result
                        ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
                    } else {
                        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);
                    }
                }
            });

            break;
        case PROVIDER:
            //LogisticsCenter.completion方法中存入的
            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;
   }

navigation可以傳入Context或者不傳,不傳的話(huà)默認(rèn)就用Application的context,每開(kāi)啟一個(gè)Activity就會(huì)新開(kāi)一個(gè)task。建議普通界面跳轉(zhuǎn)都傳入Activity,避免棧的混亂。

至此整個(gè)路由跳轉(zhuǎn)的過(guò)程大致完成,整個(gè)過(guò)程可以分為:封裝Postcard -> 查找信息集合,實(shí)例化目標(biāo)類(lèi) -> 返回實(shí)例或者跳轉(zhuǎn)。

Interceptor

前面我們跳過(guò)了攔截過(guò)程,現(xiàn)在我們來(lái)分析下這個(gè)過(guò)程,攔截功能是通過(guò)ARouter提供的interceptorService實(shí)現(xiàn)的,并且之前我們?cè)趇nit章節(jié)分析它的初始化,接下來(lái)看看具體是如何攔截的:

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);
        }
    }
});

可以看到調(diào)用了doInterceptions方法,在看這個(gè)方法之前,我們先要了解一個(gè)類(lèi):CountDownLatch。相關(guān)資料:CountDownLatch理解一:與join的區(qū)別

簡(jiǎn)單來(lái)說(shuō)CountDownLatch可以阻塞一個(gè)線(xiàn)程,知道內(nèi)部計(jì)數(shù)器為0時(shí),才繼續(xù)執(zhí)行阻塞的線(xiàn)程,計(jì)數(shù)器的初始值通過(guò)構(gòu)造傳入,通過(guò)調(diào)用countDown()方法減少一個(gè)計(jì)數(shù)。

攔截器的方法中,其中就使用CancelableCountDownLatch類(lèi),它繼承自CountDownLatch,并擴(kuò)展了cancel方法,用于直接將計(jì)數(shù)歸0,放開(kāi)阻塞:

public void cancel() {
    while (getCount() > 0) {
        countDown();
    }
}

我們回到攔截器的doInterceptions方法:

@Override
public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
    if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
        ... //省略同步等待初始化
        LogisticsCenter.executor.execute(new Runnable() {
            @Override
            public void run() {
                CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
                try {
                    _excute(0, interceptorCounter, postcard);
                    //阻塞線(xiàn)程直到超時(shí),或者計(jì)數(shù)歸0
                    interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
                    if (interceptorCounter.getCount() > 0) { //攔截超時(shí)
                        callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
                    } else if (null != postcard.getTag()) {  // 被攔截
                        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) {
    //有下一個(gè)攔截器
    if (index < Warehouse.interceptors.size()) {
        IInterceptor iInterceptor = Warehouse.interceptors.get(index);
        iInterceptor.process(postcard, new InterceptorCallback() {
            @Override
            public void onContinue(Postcard postcard) {
                // 如果放行,則計(jì)數(shù)減1,執(zhí)行后一個(gè)攔截器
                counter.countDown();
                _excute(index + 1, counter, postcard); 
            }

            @Override
            public void onInterrupt(Throwable exception) {
                // 攔截,將exception存入postcard的tag字段,計(jì)數(shù)歸零
                postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());
                counter.cancel();
            });
        }
    }

首先會(huì)創(chuàng)建一個(gè)與攔截器數(shù)量相同的CancelableCountDownLatch初始計(jì)數(shù)值,每放行一個(gè)攔截器就countDown,并交給后一個(gè)攔截器,如果攔截則清0計(jì)數(shù),并將攔截的Throwable存入postcard的tag字段,interceptorCounter.await();阻塞直到計(jì)數(shù)歸0或者阻塞超時(shí)(默認(rèn)是300秒),最后通過(guò)interceptorCounter.getCount()判斷是否是超時(shí),還是攔截或者放行。

可以看到攔截的過(guò)程都是在子線(xiàn)程中處理,包括Interceptor的process也是在子線(xiàn)程調(diào)用的,因此,如果想要在攔截過(guò)程中展示dialog等都需要切換到主線(xiàn)程。

inject

通過(guò)@Autowired注解的屬性,通過(guò)調(diào)用ARouter.getInstance().inject(this);可以實(shí)現(xiàn)自動(dòng)注入。我們知道原生的Activity傳遞數(shù)據(jù)是通過(guò)Bundle攜帶的。因此,ARouter的數(shù)據(jù)傳遞肯定也是基于Bundle,并實(shí)現(xiàn)了自動(dòng)賦值的功能。

同樣的,我們從方法入口層層深入探究:

static void inject(Object thiz) {
    AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
    if (null != autowiredService) {
        autowiredService.autowire(thiz);
    }
}

AutowiredService與InterceptorService類(lèi)似,都是Arouter自己實(shí)現(xiàn)的繼承IProvider接口的服務(wù)。我們找到AutowiredService的實(shí)現(xiàn)類(lèi):

@Route(path = "/arouter/service/autowired")
public class AutowiredServiceImpl implements AutowiredService {
    private LruCache<String, ISyringe> classCache;
    private List<String> blackList;

    @Override
    public void init(Context context) {
        classCache = new LruCache<>(66);
        blackList = new ArrayList<>();
    }

    @Override
    public void autowire(Object instance) {
        String className = instance.getClass().getName();
        try {
            if (!blackList.contains(className)) {
                ISyringe autowiredHelper = classCache.get(className);
                if (null == autowiredHelper) {  // No cache.
                    autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
                }
                autowiredHelper.inject(instance);
                classCache.put(className, autowiredHelper);
            }
        } catch (Exception ex) {
            blackList.add(className);    // This instance need not autowired.
        }
    }
}

去掉緩存集合之后,其實(shí)很簡(jiǎn)單,核心內(nèi)容就兩句:

ISyringe autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
autowiredHelper.inject(instance);

ISyringe是一個(gè)接口:

public interface ISyringe {
    void inject(Object target);
}

它的實(shí)現(xiàn)是apt生成的,每一個(gè)帶有@Autowired注解的類(lèi)都會(huì)生成一個(gè)對(duì)應(yīng)的ISyringe的實(shí)現(xiàn),如demo中的:

//生成類(lèi)的類(lèi)名 = 目標(biāo)類(lèi)名+ "$ARouter$Autowired"(固定后綴)
public class BlankFragment$ARouter$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    //強(qiáng)轉(zhuǎn)成目標(biāo)類(lèi)
    BlankFragment substitute = (BlankFragment)target;
    //給每個(gè)注解了@Autowired的屬性賦值
    //這里的key為屬性名或者注解中給定的name
    substitute.name = substitute.getArguments().getString("name");
    // 如果存在Bundle無(wú)法攜帶的類(lèi)型,則會(huì)通過(guò)SerializationService序列化成json的String傳遞,SerializationService沒(méi)有提供默認(rèn)實(shí)現(xiàn),需要用戶(hù)自己實(shí)現(xiàn)
    if (null != serializationService) {
      substitute.obj = serializationService.parseObject(substitute.getArguments().getString("obj"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestObj>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'BlankFragment' , then you should implement 'SerializationService' to support object auto inject!");
    }
    if (null == substitute.obj) {
      Log.e("ARouter::", "The field 'obj' is null, in class '" + BlankFragment.class.getName() + "!");
    }
  }
}

注意這里賦值的操作是直接調(diào)用“目標(biāo)類(lèi)對(duì)象.屬性”的方式賦值,因此,private修飾的屬性無(wú)法通過(guò)這種方式賦值,并且在賦值時(shí)會(huì)拋出異常,被AutowiredServiceImpl的autowire方法中的try-catch捕獲,存入不需要注入的集合中,最終導(dǎo)致同一個(gè)類(lèi)中的其他非private屬性也無(wú)法注入。

其注入原理基本與ButterKnife類(lèi)似。前面分析navigation的時(shí)候我們看到了將Uri參數(shù)存入Bundle的過(guò)程(或者由用戶(hù)手動(dòng)調(diào)用withXX存入bundle),此處則是將Bundle中的數(shù)據(jù)取出,并賦值給@Autowired注解的屬性。

原文鏈接:http://www.itdecent.cn/p/bc4c34c6a06c

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容