Android路由方案ARouter分析

一燃少、路由方案

原生的路由方案缺點(diǎn):

  • 顯式:直接的類依賴掖桦,耦合嚴(yán)重

  • 隱式:規(guī)則集中式管理,協(xié)作困難

  • Manifest擴(kuò)展性較差

  • 跳轉(zhuǎn)過(guò)程無(wú)法控制

  • 失敗無(wú)法降級(jí)

ARouter的優(yōu)勢(shì):

  • 使用注解供汛,實(shí)現(xiàn)了映射關(guān)系自動(dòng)注冊(cè) 與 分布式路由管理

  • 編譯期間處理注解,并生成映射文件涌穆,沒(méi)有使用反射怔昨,不影響運(yùn)行時(shí)性能

  • 映射關(guān)系按組分類、多級(jí)管理宿稀,按需初始化

  • 靈活的降級(jí)策略趁舀,每次跳轉(zhuǎn)都會(huì)回調(diào)跳轉(zhuǎn)結(jié)果,避免StartActivity()一旦失敗將會(huì)拋出運(yùn)營(yíng)級(jí)異常

  • 自定義攔截器祝沸,自定義攔截順序矮烹,可以對(duì)路由進(jìn)行攔截,比如登錄判斷和埋點(diǎn)處理

  • 支持依賴注入罩锐,可單獨(dú)作為依賴注入框架使用奉狈,從而實(shí)現(xiàn) 跨模塊API調(diào)用

  • 支持直接解析標(biāo)準(zhǔn)URL進(jìn)行跳轉(zhuǎn),并自動(dòng)注入?yún)?shù)到目標(biāo)頁(yè)面中

  • 支持獲取Fragment

  • 支持多模塊使用涩惑,支持組件化開(kāi)發(fā)

…….

這么多好處仁期,是時(shí)候來(lái)了解一下ARouter了。

二竭恬、ARouter框架

上圖是根據(jù)ARouter一次基本的路由導(dǎo)航過(guò)程跛蛋,整理的基本框架圖,涉及到主要流程痊硕,下面進(jìn)行詳細(xì)介紹赊级。

三、路由管理

1.注冊(cè)

通過(guò)注解岔绸,在編譯時(shí)收集使用了注解的類或變量并經(jīng)過(guò)Android Process Tool處理進(jìn)行統(tǒng)一管理理逊。

包含三種注解@Autowired,@Interceptor亭螟,@Route挡鞍。

@Route

注解定義

String path();//路徑URL字符串
String group() default "";//組名,默認(rèn)為一級(jí)路徑名预烙;一旦被設(shè)置墨微,跳轉(zhuǎn)時(shí)必須賦值
String name() default "undefined";//該路徑的名稱,用于產(chǎn)生JavaDoc
int extras() default Integer.MIN_VALUE;//額外配置的開(kāi)關(guān)信息扁掸;譬如某些頁(yè)面是否需要網(wǎng)絡(luò)校驗(yàn)翘县、登錄校驗(yàn)等
int priority() default -1;//該路徑的優(yōu)先級(jí)

實(shí)現(xiàn) @Route 注解

BlankFragment               @Route(path = "/test/fragment") 
Test1Activity               @Route(path = "/test/activity1")

該注解主要用于描述路由中的路徑URL信息最域,使用該注解標(biāo)注的類將被自動(dòng)添加至路由表中。

@Autowired

注解定義

boolean required() default false;
String desc() default "No desc.";

實(shí)現(xiàn) @Autowired 注解

@Autowired
int age = 10;
@Autowired
HelloService helloService;

該注解是在頁(yè)面跳轉(zhuǎn)時(shí)參數(shù)傳遞用的锈麸。目標(biāo)Class中使用該注解標(biāo)志的變量镀脂,會(huì)在頁(yè)面被路由打開(kāi)的時(shí)候,在調(diào)用inject()后自動(dòng)賦予傳遞的參數(shù)值忘伞。

@Interceptor

注解定義

int priority();//該攔截器的優(yōu)先級(jí)
String name() default "Default";//該攔截器的名稱薄翅,用于產(chǎn)生JavaDoc

實(shí)現(xiàn) @Interceptor 注解

一般應(yīng)用于IInterceptor的實(shí)現(xiàn)類,是路由跳轉(zhuǎn)過(guò)程中的攔截器氓奈,不分module翘魄,應(yīng)用全局。

@Interceptor(priority = 7)
public class Test1Interceptor implements IInterceptor {
    @Override
    public void process(final Postcard postcard, final InterceptorCallback callback) {
    ............
    }
}

2.收集

在編譯期間自動(dòng)生成映射文件舀奶,arouter-compiler實(shí)現(xiàn)了一些注解處理器,目標(biāo)在于生成映射文件與輔助文件暑竟。


三種類型的注解處理器,都實(shí)現(xiàn)了AbstractProcessor,主要功能如下:

  • 首先通過(guò)注解處理器掃出被標(biāo)注的類文件

  • 按照不同種類的源文件進(jìn)行分類

  • 按照固定的命名格式生成映射文件

這樣就可以在運(yùn)行期初始化的時(shí)候通過(guò)固定的包名來(lái)加載映射文件育勺。

關(guān)于注解處理的源碼詳解見(jiàn)阿里路由框架--ARouter 源碼解析之Compiler但荤。


以官方demo為例,通過(guò)注解處理器涧至,按照固定的命名格式生成映射文件腹躁。

具體以ARouter$$Root$$app為例,看下注解處理器生成的類文件的內(nèi)容:

public class ARouter$$Root$$app implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("service", ARouter$$Group$$service.class);
    routes.put("test", ARouter$$Group$$test.class);
  }
}

通過(guò)調(diào)用loadInto()方法將其管理的group類文件加載到集合中南蓬,方便后續(xù)路由查找潜慎。

3.加載

前面的收集都是在編譯器處理獲得的,那么加載就是到了運(yùn)行期蓖康。ARouter為了避免內(nèi)存和性能損耗铐炫,提出了“分組管理,按需加載”的方式蒜焊。在前面的編譯處理的過(guò)程中倒信,已經(jīng)按照不同種類生成對(duì)應(yīng)的映射文件。

以官方demo為示例泳梆,一個(gè)app模塊有一個(gè)Root結(jié)點(diǎn)鳖悠,管理各個(gè)Group分組,每個(gè)Group分組下有著多個(gè)界面优妙;此外app模塊下還有著Interceptor結(jié)點(diǎn)乘综,以及provider結(jié)點(diǎn)。

其中Interceptor結(jié)點(diǎn)對(duì)應(yīng)于自定義的攔截器套硼,provider結(jié)點(diǎn)對(duì)應(yīng)于IOC卡辰,以實(shí)現(xiàn)跨模塊API調(diào)用。

ARouter在初始化的時(shí)候只會(huì)一次性地加載所有的root結(jié)點(diǎn),而不會(huì)加載任何一個(gè)Group結(jié)點(diǎn)九妈,這樣就會(huì)極大地降低初始化時(shí)加載結(jié)點(diǎn)的數(shù)量反砌。當(dāng)某一個(gè)分組下的某一個(gè)頁(yè)面第一次被訪問(wèn)的時(shí)候,整個(gè)分組的全部頁(yè)面都會(huì)被加載進(jìn)去萌朱。

初始加載

ARouter 其實(shí)是一個(gè)代理類宴树,它的所有函數(shù)實(shí)現(xiàn)都交給_ARouter去實(shí)現(xiàn),兩個(gè)都是單例模式晶疼。

public static void init(Application application) {//靜態(tài)函數(shù)進(jìn)行初始化酒贬,不依賴對(duì)象
    if (!hasInit) {
        logger = _ARouter.logger; //持有 日志打印的 全局靜態(tài)標(biāo)量
        _ARouter.logger.info(Consts.TAG, "ARouter init start.");//打印 ARouter初始化日志
        hasInit = _ARouter.init(application);//移交 _ARouter去 初始化

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

        _ARouter.logger.info(Consts.TAG, "ARouter init over.");//打印 ARouter初始化日志
    }
}

繼續(xù)看一下_ARouter的初始化方法

protected static synchronized boolean init(Application application) {
        mContext = application;// Application的上下文
        LogisticsCenter.init(mContext, executor);//移交邏輯中心進(jìn)行初始化,并傳入線城池對(duì)象
        logger.info(Consts.TAG, "ARouter init success!");//打印日志
        hasInit = true;//標(biāo)示是否初始化完成

        // It's not a good idea.
        // if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        //     application.registerActivityLifecycleCallbacks(new AutowiredLifecycleCallback());
        // }
        return true;
    }

繼續(xù)往下走翠霍,看LogisticsCenter的初始化方法

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
        mContext = context; //靜態(tài)持有Application的上下文
        executor = tpe;//靜態(tài)持有 線城池

        try {
            // These class was generate by arouter-compiler.
            // 通過(guò)指定包名com.alibaba.android.arouter.routes同衣,找到所有 編譯期產(chǎn)生的routes目錄下的類名(不包含裝載類)
            List<String> classFileNames = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);

            for (String className : classFileNames) {//組別列表com.alibaba.android.arouter.routes.ARouter\$\$Root
                if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                    // This one of root elements, load root.
                    ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {//模塊內(nèi)的攔截器列表com.alibaba.android.arouter.routes.ARouter\$\$Interceptors
                    // Load interceptorMeta
                    ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {//IOC的動(dòng)作路由列表com.alibaba.android.arouter.routes.ARouter\$\$Providers
                    // Load providerIndex
                    ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                }
            }

            if (Warehouse.groupsIndex.size() == 0) {
                logger.error(TAG, "No mapping files were found, check your configuration please!");
            }

            if (ARouter.debuggable()) {
                logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));
            }
        } catch (Exception e) {
            throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
        }
    }

通過(guò)上述代碼,實(shí)現(xiàn)了“分組管理壶运,按需加載”的方式,加載了對(duì)應(yīng)的三個(gè)注解處理器生成的類中管理的結(jié)點(diǎn)到路由集合中浪秘。


其中內(nèi)存?zhèn)}庫(kù)Warehouse緩存了全局應(yīng)用的組別的清單列表蒋情、IOC的動(dòng)作路由清單列表、模塊內(nèi)的攔截器清單列表耸携,3個(gè)map對(duì)象棵癣。

class Warehouse {
    // Cache route and metas
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();//組別的列表 包含了組名與對(duì)應(yīng)組內(nèi)的路由清單列表Class的映射關(guān)系
    static Map<String, RouteMeta> routes = new HashMap<>();//組內(nèi)的路由列表 包含了對(duì)應(yīng)分組下的,路由URL與目標(biāo)對(duì)象Class的映射關(guān)系

    // Cache provider
    static Map<Class, IProvider> providers = new HashMap<>(); //緩存IOC  目標(biāo)class與已經(jīng)創(chuàng)建了的對(duì)象 
    
    static Map<String, RouteMeta> providersIndex = new HashMap<>();//IOC 的動(dòng)作路由列表包含了使用依賴注入方式的某class的  路由URL 與class映射關(guān)系

    // Cache interceptor
    //模塊內(nèi)的攔截器列表 包含了某個(gè)模塊下的攔截器 與 優(yōu)先級(jí)的映射關(guān)系
    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
    static List<IInterceptor> interceptors = new ArrayList<>();//已排序的攔截器實(shí)例對(duì)象
 
}

四夺衍、路由查找

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

以上述例子為例狈谊,看一下ARouter路由查找的過(guò)程。首先看一下build過(guò)程

1.build()

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

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

其使用了代理類_ARouter的build()并構(gòu)建和返回PostCard對(duì)象沟沙。 一個(gè)Postcard對(duì)象就對(duì)應(yīng)了一次路由請(qǐng)求河劝,作用于本次路由全過(guò)程。

這部分代碼主要包含兩個(gè)部分:

  • 使用 IOC byType()方式尋找PathReplaceService.class接口的實(shí)現(xiàn)類矛紫,該實(shí)現(xiàn)類的作用就是實(shí)現(xiàn) “運(yùn)行期動(dòng)態(tài)修改路由”赎瞎。
  • 繼續(xù)進(jìn)行本次路由導(dǎo)航

首先來(lái)看一下PathReplaceService.class接口:

public interface PathReplaceService extends IProvider {

    /**
     * For normal path.
     *
     * @param path raw path
     */
    String forString(String path);

    /**
     * For uri type.
     *
     * @param uri raw uri
     */
    Uri forUri(Uri uri);
}

主要包含forString()和forUri兩個(gè)方法,針對(duì)路徑進(jìn)行預(yù)處理颊咬,實(shí)現(xiàn) “運(yùn)行期動(dòng)態(tài)修改路由”务甥。

接下下,繼續(xù)通過(guò)build(path, extractGroup(path))進(jìn)行路由導(dǎo)航喳篇,其中extractGroup()是從路徑中獲取默認(rèn)的分組信息敞临。

然后build()方法會(huì)返回一個(gè)Postcard對(duì)象,并把對(duì)應(yīng)的路徑和分組信息傳入該對(duì)象麸澜。

分析完上面的過(guò)程挺尿,下面來(lái)詳細(xì)看下PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);中的navigation()方法,該方法實(shí)際調(diào)用了代理類_ARouter的navigation(Class<? extends T> service)方法。

2.navigation(Class<? extends T> service)

protected <T> T navigation(Class<? extends T> service) {
    try {
        Postcard postcard = LogisticsCenter.buildProvider(service.getName());

        // Compatible 1.0.5 compiler sdk.
        if (null == postcard) { // No service, or this service in old version.
            postcard = LogisticsCenter.buildProvider(service.getSimpleName());
        }

        LogisticsCenter.completion(postcard);
        return (T) postcard.getProvider();
    } catch (NoRouteFoundException ex) {
        logger.warning(Consts.TAG, ex.getMessage());
        return null;
    }
}
  • 首先LogisticsCenter.buildProvider(service.getName())根據(jù)Warehouse保存的providersIndex的信息查找并構(gòu)建返回一個(gè)PostCard對(duì)象

  • 然后執(zhí)行LogisticsCenter.completion(postcard)票髓,該方法會(huì)根據(jù)Warehouse保存的routes的路由信息完善postcard對(duì)象攀涵,該方法在下面還會(huì)出現(xiàn),到時(shí)候具體介紹

再回到上文介紹ARouter.getInstance().build("/test/activity2").navigation()洽沟,返回PostCard對(duì)象后以故,開(kāi)始調(diào)用對(duì)應(yīng)的navigation()方法。

3.navigation()

觀察PostCard中的該方法

public Object navigation() {
        return navigation(null);
    }
    
    public Object navigation(Context context) {
        return navigation(context, null);
    }

    public Object navigation(Context context, NavigationCallback callback) {
        return ARouter.getInstance().navigation(context, this, -1, callback);
    }

    public void navigation(Activity mContext, int requestCode) {
        navigation(mContext, requestCode, null);
    }

    public void navigation(Activity mContext, int requestCode, NavigationCallback callback) {
        ARouter.getInstance().navigation(mContext, this, requestCode, callback);
    }

最終調(diào)用了ARouter中的navigation()方法裆操,在其中其實(shí)是調(diào)用了_ARouter中的navigation()方法怒详。

該方法包含查找回調(diào)的調(diào)用、降級(jí)處理踪区、攔截器處理具體路由操作昆烁。

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        try {
            LogisticsCenter.completion(postcard);
        } catch (NoRouteFoundException ex) {
            logger.warning(Consts.TAG, ex.getMessage());

            if (debuggable()) { // Show friendly tips for user.
                Toast.makeText(mContext, "There's no route matched!\n" +
                        " Path = [" + postcard.getPath() + "]\n" +
                        " Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
            }
    
            if (null != callback) {
                callback.onLost(postcard);//觸發(fā)路由查找失敗
            } else {    // No callback for this invoke, then we use the global degrade service.
                DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
                if (null != degradeService) {
                    degradeService.onLost(context, postcard);
                }
            }

            return null;
        }
        //找到了路由元信息,觸發(fā)路由查找的回調(diào)
        if (null != callback) {
            callback.onFound(postcard);
        }
        //綠色通道校驗(yàn) 需要攔截處理
        if (!postcard.isGreenChannel()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.
            //調(diào)用攔截器截面控制器缎岗,遍歷內(nèi)存?zhèn)}庫(kù)的自定義攔截器静尼,并在異步線程中執(zhí)行攔截函數(shù)
            interceptorService.doInterceptions(postcard, new InterceptorCallback() {
                /**
                 * Continue process
                 *
                 * @param postcard route meta
                 */
                @Override
                public void onContinue(Postcard postcard) {
                    _navigation(context, postcard, requestCode, callback);
                }

                /**
                 * Interrupt process, pipeline will be destory when this method called.
                 *
                 * @param exception Reson of interrupt.
                 */
                @Override
                public void onInterrupt(Throwable exception) {
                    if (null != callback) {
                        callback.onInterrupt(postcard);
                    }

                    logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
                }
            });
        } else {
            return _navigation(context, postcard, requestCode, callback);
        }

        return null;
    }

其中最重要的兩個(gè)方法就是LogisticsCenter.completion()_navigation(),下面詳細(xì)介紹传泊。

public synchronized static void completion(Postcard postcard) {
    if (null == postcard) {
        throw new NoRouteFoundException(TAG + "No postcard!");
    }
    //根據(jù)路徑URL獲取到路徑元信息
    RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
    if (null == routeMeta) {    // Maybe its does't exist, or didn't load.
        //可能沒(méi)加載組內(nèi)清單路徑鼠渺,從組別的清單列表拿到對(duì)應(yīng)組
        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() + "]");
        } else {
            //將該組的組內(nèi)清單列表加入到內(nèi)存?zhèn)}庫(kù)中,并把組別移除
            try {
                if (ARouter.debuggable()) {
                    logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                }

                IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                iGroupInstance.loadInto(Warehouse.routes);
                Warehouse.groupsIndex.remove(postcard.getGroup());

                if (ARouter.debuggable()) {
                    logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                }
            } catch (Exception e) {
                throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
            }

            completion(postcard);   // 再次觸發(fā)完善邏輯
        }
    } else {
        postcard.setDestination(routeMeta.getDestination());//目標(biāo) class
        postcard.setType(routeMeta.getType());//路由類
        postcard.setPriority(routeMeta.getPriority());//路由優(yōu)先級(jí)
        postcard.setExtra(routeMeta.getExtra());//額外的配置開(kāi)關(guān)信息

        Uri rawUri = postcard.getUri();
        if (null != rawUri) {   // Try to set params into bundle.
            Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
            Map<String, Integer> paramsType = routeMeta.getParamsType();

            if (MapUtils.isNotEmpty(paramsType)) {
                // Set value by its type, just for params which annotation by @Param
                for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
                    setValue(postcard,
                            params.getValue(),
                            params.getKey(),
                            resultMap.get(params.getKey()));
                }

                // Save params name which need auto inject.
                postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
            }

            // Save raw uri
            postcard.withString(ARouter.RAW_URI, rawUri.toString());
        }

        switch (routeMeta.getType()) {
            case PROVIDER:  // if the route is provider, should find its instance
                // Its provider, so it must implement IProvider
                Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                IProvider instance = Warehouse.providers.get(providerMeta);
                if (null == instance) { // There's no instance of this provider
                    IProvider provider;
                    try {
                        provider = providerMeta.getConstructor().newInstance();
                        provider.init(mContext);
                        Warehouse.providers.put(providerMeta, provider);
                        instance = provider;
                    } catch (Exception e) {
                        throw new HandlerException("Init provider failed! " + e.getMessage());
                    }
                }
                postcard.setProvider(instance);
                postcard.greenChannel();    // Provider should skip all of interceptors
                break;
            case FRAGMENT:
                postcard.greenChannel();    // Fragment needn't interceptors
            default:
                break;
        }
    }
}

該方法就是完善PostCard眷细,來(lái)實(shí)現(xiàn)一次路由導(dǎo)航拦盹。

接下來(lái)介紹另一個(gè)方法_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://如果是Acitvity溪椎,則實(shí)現(xiàn)Intent跳轉(zhuǎn)
                // 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);
                }

                // Navigation in main looper.
                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://如果是IOC普舆,則返回目標(biāo)對(duì)象實(shí)例
                return postcard.getProvider();
            case BOARDCAST:
            case CONTENT_PROVIDER:
            case FRAGMENT://如果是Fragment,則返回實(shí)例校读,并填充bundle
                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;
    }

至此我們就完成了一次路由跳轉(zhuǎn)沼侣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市歉秫,隨后出現(xiàn)的幾起案子华临,更是在濱河造成了極大的恐慌,老刑警劉巖端考,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雅潭,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡却特,警方通過(guò)查閱死者的電腦和手機(jī)扶供,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)裂明,“玉大人椿浓,你說(shuō)我怎么就攤上這事。” “怎么了扳碍?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵提岔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我笋敞,道長(zhǎng)碱蒙,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任夯巷,我火速辦了婚禮赛惩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘趁餐。我一直安慰自己喷兼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布后雷。 她就那樣靜靜地躺著季惯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪臀突。 梳的紋絲不亂的頭發(fā)上勉抓,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音惧辈,去河邊找鬼。 笑死磕瓷,一個(gè)胖子當(dāng)著我的面吹牛盒齿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播困食,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼边翁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了硕盹?” 一聲冷哼從身側(cè)響起符匾,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瘩例,沒(méi)想到半個(gè)月后啊胶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垛贤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年焰坪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聘惦。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡某饰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情黔漂,我是刑警寧澤诫尽,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站炬守,受9級(jí)特大地震影響牧嫉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜劳较,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一驹止、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧观蜗,春花似錦臊恋、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至砖第,卻和暖如春撤卢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梧兼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工放吩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人羽杰。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓渡紫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親考赛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子惕澎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345