美文网首页
ARouter的路由跳转发生了什么事儿

ARouter的路由跳转发生了什么事儿

作者: VerseWang | 来源:发表于2021-03-31 20:16 被阅读0次

    在组件化的时候,组件与组件是高度解耦的,但组件与组件之间需要通信,这不得不提到ARouter

    说在前面

    ARouter.png
    // Cache route and metas
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>(); // 添加注解后将映射关系添加到这个集合当中
    static Map<String, RouteMeta> routes = new HashMap<>(); // 跳转某个路由后的缓存,包括常用的Activity,Framgent,清单文件的meta
    
    // Cache provider
    static Map<Class, IProvider> providers = new HashMap<>(); // 实现IProvider的注解后映射关系添加到这个集合中
    static Map<String, RouteMeta> providersIndex = new HashMap<>(); // IProvider的缓存
    
    // Cache interceptor
    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]"); // 实现IInterceptor的注解映射关系添加到这个集合中
    static List<IInterceptor> interceptors = new ArrayList<>(); // IInterceptor的缓存
    

    分析目标

    若需要对Activity路由,只需要添加@Route,如

    @Route(path = "/test/activity2")
    

    当添加注解后,会通过apt生成ARouter%Group%test的文件,里面包含有需要路由的相关的信息,包含一个RouteType枚举类,如

    atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test"));
    

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

    常见的有Activity,Fragment,接口实现类IProvider

    案例分析

    ARouter.init(getApplication())
    ARouter.getInstance().build("/test/activity2").navigation();
    

    这两行代码发生了什么事情

    首先看init方法

    public static void init(Application application) {
        if (!hasInit) {
            hasInit = _ARouter.init(application);
            if (hasInit) {
                _ARouter.afterInit();
            }
        }
    }
    

    hasInit默认为false

    protected static synchronized boolean init(Application application) {
        mContext = application;
        LogisticsCenter.init(mContext, executor);
        hasInit = true;
        mHandler = new Handler(Looper.getMainLooper());
        return true;
    }
    
    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
        if (registerByPlugin) {
                logger.info(TAG, "Load router map by arouter-auto-register plugin.");
            } else {
                ...
        }
    }
    

    我调试发现registerByPlugin = true,只是打印了一个log
    这里是将hasInit设置为true,代表初始化成功了,并返回true

    接着会调用_ARouter.afterInit() 这里是初始化一个 PROVIDER,仅此而已

    这里只是初始化了ARouter.init(getApplication()) 东西并不多

    接着会路由跳转,在分析之前,我先阐述下ARouter与_ARouter系,他们的关系是23种设计模式中的外观模式,_ARouter是核心类,基本上所有的逻辑都在这里面,ARouter只是包了一层,做了下方法的传递

    ARouter.getInstance().build("/test/activity2")
    

    进入到_ARouter.build()里

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

    第5行是对path做处理,由于没有添加注解,pService=null,接着调用build()

    protected Postcard build(String path, String group, Boolean afterReplace) {
        ...
        return new Postcard(path, group);
    }
    

    关键代码只有 return new Postcard(path, group),而Postcard继承的是RouteMeta,build()走完后,调用navigation()

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

    由于ARouter和_ARouter是外观设计模式,直接看_ARouter的navigation

    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
        if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
            // Pretreatment failed, navigation canceled.
            return null;
        }
    
        // Set context to postcard.
        postcard.setContext(null == context ? mContext : context);
    
        try {
            LogisticsCenter.completion(postcard);
        } catch (NoRouteFoundException ex) {
            ...
            return null;
        }
    
        if (null != callback) {
            callback.onFound(postcard);
        }
    
        if (!postcard.isGreenChannel()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.
            interceptorService.doInterceptions(postcard, new InterceptorCallback() {
                @Override
                public void onContinue(Postcard postcard) {
                    _navigation(postcard, requestCode, callback);
                }
                @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(postcard, requestCode, callback);
        }
    
        return null;
    }
    

    第2,3行代码又是一个拦截,由于没有实现,这里忽略,看第12行代码LogisticsCenter.completion(postcard);

    public synchronized static void completion(Postcard postcard) {
        RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
        if (null == routeMeta) {
            // Load route and cache it into memory, then delete from metas.
            addRouteGroupDynamic(postcard.getGroup(), null);
    
            completion(postcard);   // Reload
        } else {
            postcard.setDestination(routeMeta.getDestination());
            postcard.setType(routeMeta.getType());
            postcard.setPriority(routeMeta.getPriority());
            postcard.setExtra(routeMeta.getExtra());
    
            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) {
                            logger.error(TAG, "Init provider failed!", e);
                            throw new HandlerException("Init provider failed!");
                        }
                    }
                    postcard.setProvider(instance);
                    postcard.greenChannel();    // Provider should skip all of interceptors
                    break;
                case FRAGMENT:
                    postcard.greenChannel();    // Fragment needn't interceptors
                default:
                    break;
            }
        }
    }
    

    if 和 else里做的事情是,如果缓存中没有指定的path(第一次调用group),则走if,去解析,else 则做赋值等操作,

    public synchronized static void addRouteGroupDynamic(String groupName, IRouteGroup group) {
        if (Warehouse.groupsIndex.containsKey(groupName)){
            Warehouse.groupsIndex.get(groupName).getConstructor().newInstance().loadInto(Warehouse.routes);
            Warehouse.groupsIndex.remove(groupName);
        }
    
        // cover old group.
        if (null != group) {
            group.loadInto(Warehouse.routes);
        }
    }
    

    第3行是通过group在groupsIndex中获取class,groupsIndex是@Route注解后添加到集合的,通过反射获取对象后,将相同的group放到routes集合里,放到routes后再调用completion,则走 else

    postcard.setDestination(routeMeta.getDestination());
            postcard.setType(routeMeta.getType());
            postcard.setPriority(routeMeta.getPriority());
            postcard.setExtra(routeMeta.getExtra());
    
            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) {
                            logger.error(TAG, "Init provider failed!", e);
                            throw new HandlerException("Init provider failed!");
                        }
                    }
                    // 将实例对象放在postcard中
                    postcard.setProvider(instance); 
                    postcard.greenChannel(); 
                    break;
                case FRAGMENT:
                    postcard.greenChannel();
                default:
                    break;
            }
    

    这里做了一些赋值操作,如果是PROVIDER且providers缓存集合里没有时,通过返回获取实例以后会调用init()方法,并将对象放到providers缓存集合中

    至此,Postcard初始化完成

    if (!postcard.isGreenChannel()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.
            interceptorService.doInterceptions(postcard, new InterceptorCallback() {
                @Override
                public void onContinue(Postcard postcard) {
                    _navigation(postcard, requestCode, callback);
                }
                @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(postcard, requestCode, callback);
        }
    

    这里是调用了拦截器,若注解了拦截器,会先走拦截器里实现的逻辑,在调用onContinue方法的_navigation方法

    private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        final Context currentContext = postcard.getContext();
    
        switch (postcard.getType()) {
            case ACTIVITY:
                final Intent intent = new Intent(currentContext, postcard.getDestination());
                intent.putExtras(postcard.getExtras());
                ...
                runInMainThread(new Runnable() {
                    @Override
                    public void run() {
                        startActivity(requestCode, currentContext, intent, postcard, callback);
                    }
                });
    
                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;
    }
    

    若是ACTIVITY,则跳转到activity,
    若是PROVIDER,则返回IProvider对象,
    若是BOARDCAST,CONTENT_PROVIDER,FRAGMENT,则返回Fragment对象

    总结

    若是路由的是Activity,则直接跳转到指定的Activity,若是其他的,则获取实例后进行其他逻辑的处理

    相关文章

      网友评论

          本文标题:ARouter的路由跳转发生了什么事儿

          本文链接:https://www.haomeiwen.com/subject/mtmahltx.html