美文网首页
Arouter之API原理解析

Arouter之API原理解析

作者: jxiang112 | 来源:发表于2022-04-10 00:52 被阅读0次

    Arouter是什么及其注解处理器的原理在文章:Arouter之注解器处理器原理解析中有说明,建议先去看这篇文章,因为API原理解析依赖注解处理器生成的:路由表类文件、依赖注入辅助工具类文件、拦截器表类文件。

    Arouter

    Arouter类是Arouter框架的门面类,暴露接口给开发者调用,其所有方法都是调用_Arouter对应的方法。
    我看下几个下几个常用的方法的源码:

    public final class ARouter {
        private volatile static ARouter instance = null;
        
        public static void init(Application application) {
            //初始化Arouter,其内部调用的是_Arouter进行初始化
            if (!hasInit) {
                logger = _ARouter.logger;
                _ARouter.logger.info(Consts.TAG, "ARouter init start.");
                //调用的是_Arouter进行初始化
                hasInit = _ARouter.init(application);
    
                if (hasInit) {
                   //初始化成功,调用_Arouter的afterInit方法
                    _ARouter.afterInit();
                }
    
                _ARouter.logger.info(Consts.TAG, "ARouter init over.");
            }
        }
    
        public static ARouter getInstance() {
            //获取Arouter单例
            if (!hasInit) {
                //未初始化,则抛出异常
                throw new InitException("ARouter::Init::Invoke init(context) first!");
            } else {
                //已初始化,则创建Arouter单例
                if (instance == null) {
                    synchronized (ARouter.class) {
                        if (instance == null) {
                            instance = new ARouter();
                        }
                    }
                }
                return instance;
            }
        }
    
        public void inject(Object thiz) {
            //调用_ARouter的注入方法
            _ARouter.inject(thiz);
        }
    
        public Postcard build(String path) {
            //调用_ARouter单例通过路由路径构建路由明信片Postcard 
            return _ARouter.getInstance().build(path);
        }
    
        public Postcard build(Uri url) {
            //调用_ARouter单例通过路由url构建路由明信片Postcard 
            return _ARouter.getInstance().build(url);
        }
    
        public <T> T navigation(Class<? extends T> service) {
            //调用_ARouter单例通过服务Class导航到具体的服务,并返回服务对象
            return _ARouter.getInstance().navigation(service);
        }
    
        public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
             //调用_ARouter单例通过路由明信片导航到具体的路由,requestCode是startActivityForResult的requestCode
            return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
        }
    }
    

    根据Arouter的核心源码部分,我们得出如下结论:
    1、使用Arouter之前,必须先进行初始化,否则会抛出未初始化的异常
    2、Arouter的是作为_Arouter的门面,内部调用的是_Arouter对应的方法

    Arouter初始化

    Arouter的初始哈的真实实现是在_Arouter的init方法:

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

    _Arouter的初始化接着调用LogisticsCenter的初始化方法:

    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
            mContext = context;
            executor = tpe;
    
            try {
                long startInit = System.currentTimeMillis();
                //load by plugin first
                loadRouterMap();
                if (registerByPlugin) {
                    //如果使用了自动注册插件,则啥也不做
                    logger.info(TAG, "Load router map by arouter-auto-register plugin.");
                } else {
                    //如果没有使用自动注册插件,则需要完成RoutGroup、Provider、Interceptor的注册
                    //路由文件集合(包括:RouteRoot、Provider、Interceptor),值为类全限定名
                    Set<String> routerMap;
    
                    // It will rebuild router map every times when debuggable.
                    if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
                        //当前应用是新版本,重新从apk的dex中读取路由文件集合
                        logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
                        // These class was generated by arouter-compiler.
                        //从apk的dex中读取所有的路由文件集合
                        routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
                        if (!routerMap.isEmpty()) {
                            //路由文件集合不为空,则将路由文件集合缓存到SharedPreferences中
                            context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
                        }
                        //更新缓存中路由文件集合的版本
                        PackageUtils.updateVersion(context);    // Save new version name when router map update finishes.
                    } else {
                        //当前应用不是新版本,从缓存中读取路由文件集合
                        logger.info(TAG, "Load router map from cache.");
                        routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
                    }
    
                    logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
                    startInit = System.currentTimeMillis();
    
                    for (String className : routerMap) {
                        //遍历路由文件集合
                        if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                            // This one of root elements, load root.
                            //如果路由文件类型为RouteRoot类型,反射创建RouteRoot对象,并调用其loadInto方法将路由组加载到全局路由组表Warehouse.groupsIndex中
                            ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                            //如果路由文件类型为Interceptor类型,反射创建Interceptor对象,并调用其loadInto方法将拦截器加载到全局拦截器表Warehouse.interceptorsIndex中
                            // Load interceptorMeta
                            ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                            // Load providerIndex
                            //如果路由文件类型为Provider类型,反射创建Provider对象,并调用其loadInto方法将provider加载到全局服务表Warehouse.providersIndex中
                            ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                        }
                    }
                }
               //.....
            } catch (Exception e) {
              //.....
            }
        }
    

    根据上述源码的解析,我们可以得出以下结论:
    1、Arouter的初始化最终进入LogisticsCenter的init方法实现初始化
    2、初始化的工作主要是:

    • 设置全局context
    • 如果没有使用自动注册插件,那么就是将注解器生成的路由组RouteRoot文件、拦截器文件InterceptorGroup、服务Provider注册到全局变量中,全局变量分别是:
      • Warehouse.groupsIndex:路由组表,key是组名,value是路由组RouteGroup的Class
      • Warehouse.interceptorsIndex:拦截器列表,key是拦截器优先级,value是拦截器InterceptorGroup的class
      • Warehouse.providersIndex:服务表,key是服务器类全限定名,value是描述服务的路由元RouteMeta对象

    Arouter导航

    Arouter的导航可以实现:打开指定路由的Activity、获取指定路由的Fragment/ContentProvider/Boardcast、获取指定路由的Provider。导航的方式分为

    • 根据路由路径path进行导航
    • 根据uri进行导航
    • 根据服务的class进行导航
    路径导航

    我们先看通过路径进行导航的源码流程:
    Arouter的build(path)和build(path, group)都会进入_Arouter对应的方法,我们直接看_Arouter对应的方法:

    protected Postcard build(String path) {
            if (TextUtils.isEmpty(path)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
                //这一步主要主要是路由重定向,就是把path转换为其它的路由路径
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    path = pService.forString(path);
                }
                //第二个参数extractGroup取paht的第一段//作为组名
                //第三个参数表示是经过重定向的
                return build(path, extractGroup(path), true);
            }
        }
    protected Postcard build(String path, String group, Boolean afterReplace) {
            //构建路由明信片Postcard 
            if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
                //路由路径或者路由组为空,抛出异常
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            } else {
                if (!afterReplace) {
                    //如果没有经过重定向,则进行重定向
                    PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                    if (null != pService) {
                        path = pService.forString(path);
                    }
                }
                //通过路由路径和组名创建路由明信片Postcard
                return new Postcard(path, group);
            }
        }
    

    构建出路由明信片Postcard之后,调用Postcard的导航方法navigation继续完成导航:

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

    最终调用_Arouter的navigation(mContext, postcard, requestCode, callback)方法:

    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.
            //明信片设置上下文context
            postcard.setContext(null == context ? mContext : context);
    
            try {
                //构建路由明信片的完整信息,如路由具体信息、路由需要依赖注入的参数等
                LogisticsCenter.completion(postcard);
            } catch (NoRouteFoundException ex) {
               //......
               //导航失败
                if (null != callback) {
                    //回调导航失败
                    callback.onLost(postcard);
                } 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;
            }
    
            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() {
                    /**
                     * Continue process
                     *
                     * @param postcard route meta
                     */
                    @Override
                    public void onContinue(Postcard postcard) {
                        //没有拦截器拦截当前路由,则调用_navigation继续完成路由导航
                        _navigation(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 {
                //绿色通道,直接调用_navigation继续完成路由导航
                return _navigation(postcard, requestCode, callback);
            }
    
            return null;
        }
    

    我们先看LogisticsCenter怎么完善明信片的信息:

    public synchronized static void completion(Postcard postcard) {
           //.....
            //根据路由路径,从路由表中获取路由信息
            RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
            if (null == routeMeta) {
                //未加载路由
                // Maybe its does't exist, or didn't load.
                if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {
                    //如果路由组中没有匹配的路由,则抛出异常
                    throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
                } else {
                    // Load route and cache it into memory, then delete from metas.
                    try {
                       //......
                        //动态的将路由组中路由都加载到路由表中
                        addRouteGroupDynamic(postcard.getGroup(), null);
    
                       //......
                    } catch (Exception e) {
                        throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
                    }
                    //加载完路由,重新调用completion完善路由明信片
                    completion(postcard);   // Reload
                }
            } else {
                //已加载路由
                //设置路由class
                postcard.setDestination(routeMeta.getDestination());
                //设置路由类型
                postcard.setType(routeMeta.getType());
                //设置路由优先级
                postcard.setPriority(routeMeta.getPriority());
                //设置路由附加信息
                postcard.setExtra(routeMeta.getExtra());
                
                Uri rawUri = postcard.getUri();
                if (null != rawUri) {   // Try to set params into bundle.
                    //如果通过Uri导航,则将uri中的query转为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
                        //根据需要依赖注入的参数类型列表构建出传递给路由的参数值Bundle
                        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
                    //将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
                        //如果路由类型是Provider类型,则:
                        //反射创建服务实现类,并放入全局服务表Warehouse.providers中
                        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
                                provider.init(mContext);
                                //将provider放入全球服务表Warehouse.providers中
                                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);
                        //所有的provider都不需要拦截,直接设置为绿色通道
                        postcard.greenChannel();    // Provider should skip all of interceptors
                        break;
                    case FRAGMENT:
                        //所有的fragment不需要拦截,直接设置为绿色通道
                        postcard.greenChannel();    // Fragment needn't interceptors
                    default:
                        break;
                }
            }
        }
    
    public synchronized static void addRouteGroupDynamic(String groupName, IRouteGroup group) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            //动态加载路由组,将路由组内的路由加入全局路由表Warehouse.routes中
            if (Warehouse.groupsIndex.containsKey(groupName)){\
               //如果存在路由组RouteGroup,则:
                // If this group is included, but it has not been loaded
                // load this group first, because dynamic route has high priority.
                //从全局路由组表Warehouse.groupsIndex中获取路由组的class,通过反射创建路由组对象,并调用loadInto方法将组内的路由将入全局路由表Warehouse.routes中
    Warehouse.groupsIndex.get(groupName).getConstructor().newInstance().loadInto(Warehouse.routes);
                Warehouse.groupsIndex.remove(groupName);
            }
    
            // cover old group.
            if (null != group) {
                group.loadInto(Warehouse.routes);
            }
        }
    

    LogisticsCenter的completion是通过从全局路由组表反射Warehouse.groupsIndex中的路由组RouteGroup对象,并调用RouteGroup对象的loadInto将组内路由加入全局路由表Warehouse.routes,接着从路由表中获取路由元对象RouteMeta的信息来填充完善路由明信片postcard对象,包括目标路由的class、目标路由需要注入的参数列表及其参数值、目标provider等。
    我们接着来分析上面导航时没有被拦截,需要继续完成导航的_Arouter的_navigation的源码:

    private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            //获取上下文context:activity或者applicationcontext
            final Context currentContext = postcard.getContext();
    
            switch (postcard.getType()) {
                case ACTIVITY:
                    // Build intent
                    //如果目标路由是activity,则:
                    //创建activity的意图intent,class是路由名片中目标路由activity的class
                    final Intent intent = new Intent(currentContext, postcard.getDestination());
                    //设置意图的参数,即需要依赖注入的字段列表及其参数值
                    intent.putExtras(postcard.getExtras());
    
                    // Set flags.
                    //设置意图标志位
                    int flags = postcard.getFlags();
                    if (0 != flags) {
                        intent.setFlags(flags);
                    }
    
                    // Non activity, need FLAG_ACTIVITY_NEW_TASK
                    if (!(currentContext instanceof Activity)) {
                        //如果上下文不是activity,则需要在新的栈中打开activity
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    }
    
                    // Set Actions
                    //设置intent的action
                    String action = postcard.getAction();
                    if (!TextUtils.isEmpty(action)) {
                        intent.setAction(action);
                    }
                  
                    // Navigation in main looper.
                    runInMainThread(new Runnable() {
                        @Override
                        public void run() {
                            //回到主线程打开activity
                            startActivity(requestCode, currentContext, intent, postcard, callback);
                        }
                    });
    
                    break;
                case PROVIDER:
                    //如果目标路由是provider类型,则:
                    //直接返回目标路由提供的服务对象
                    return postcard.getProvider();
                case BOARDCAST:
                case CONTENT_PROVIDER:
                case FRAGMENT:
                    //如果目标路由是fragment/contentProvider/Boardcast,则:
                    //获取目标路由的class
                    Class<?> fragmentMeta = postcard.getDestination();
                    try {
                         //通过class反射目标路由对象
                        Object instance = fragmentMeta.getConstructor().newInstance();
                        if (instance instanceof Fragment) {
                             //如果是fragment,则设置参数及其参数值
                            ((Fragment) instance).setArguments(postcard.getExtras());
                        } else if (instance instanceof android.support.v4.app.Fragment) {
                            //如果是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;
        }
    

    到此完成整改路由导航的流程。

    Uri导航

    我们接着看通过uri导航的源码流程:
    Arouter的build(Uri uri)会进入_Arouter对应的方法,我们直接看_Arouter对应的方法:

    protected Postcard build(Uri uri) {
            if (null == uri || TextUtils.isEmpty(uri.toString())) {
                //无效的uri抛出异常
                throw new HandlerException(Consts.TAG + "Parameter invalid!");
            } else {
                //路由重定向
                PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
                if (null != pService) {
                    uri = pService.forUri(uri);
                }
                //从uri中取出路由路径path,使用路由路径的第一段//中的字符串作为路由组名,使用path和组名创建路由明信片
                return new Postcard(uri.getPath(), extractGroup(uri.getPath()), uri, null);
            }
        }
    

    uri导航的方式是从uri中路由路径path,使用路由路径的第一段//中的字符串作为路由组名,使用path和组名创建路由明信片。创建出路由明信片之后,接下来的导航流程与上面分析的“路径导航”一样,在此不做重复介绍。

    Class导航

    我们接着看通过Class导航的流程,class导航方式只能导航到模块提供的服务,且会返回class对应的服务对象,直接使用的是navigation方法,我们来看看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.
                // Earlier versions did not use the fully qualified name to get the service
                if (null == postcard) {
                    //如果找不到路由,则
                    // No service, or this service in old version.
                    //使用服务类的简单类名(不含包名)来构建路由明信片
                    postcard = LogisticsCenter.buildProvider(service.getSimpleName());
                }
    
                if (null == postcard) {
                    //如果找不到路由,则返回空
                    return null;
                }
    
                // Set application to postcard.
                //找到路由,设置路由明信片的上下文
                postcard.setContext(mContext);
                //完善路由明信片
                LogisticsCenter.completion(postcard);
                //直接返回路由明信片中的服务对象
                return (T) postcard.getProvider();
            } catch (NoRouteFoundException ex) {
                logger.warning(Consts.TAG, ex.getMessage());
                return null;
            }
        }
    
    
    //LogisticsCenter.buildProvider
    public static Postcard buildProvider(String serviceName) {
            //根据服务类名从全局服务表Warehouse.providersIndex中取出服务对应的路由元信息对象meta 
            RouteMeta meta = Warehouse.providersIndex.get(serviceName);
    
            if (null == meta) {
                //找不到服务,返回空
                return null;
            } else {
                //找到服务,则通过路由元信息中的路由路径和组名创建路由明信片并返回
                return new Postcard(meta.getPath(), meta.getGroup());
            }
        }
    

    通过class进行导航是为获取模块提供的服务服务的,它先根据服务类名从全局服务表Warehouse.providersIndex中取出服务对应的路由元信息对象,使用此路由元信息创建对应的路由明信片对象,接着调用LogisticsCenter.completion完善路由明信片,完善的逻辑在上面的“路由导航”有分析过,在此不做重复介绍,接着返回明信片中的服务对象,完成本次导航。

    导航拦截

    在上面的路由导航分析中,在导航时有介绍到使用了拦截器对导航进行拦截处理,我们来看看拦截器的工作原理:
    首先呢,Arouter的Api中内置了一个拦截处理中心InterceptorServiceImpl,它是一个服务提供者,提供的是为导航调度所有拦截器的逻辑,我们来看看其源码:

    @Route(path = "/arouter/service/interceptor")
    public class InterceptorServiceImpl implements InterceptorService {
        //拦截器调度中心类
       //是否已初始化
        private static boolean interceptorHasInit;
       //初始化锁对象
        private static final Object interceptorInitLock = new Object();
    
        @Override
        public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
            //开始调度拦截器
            if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
                //如果拦截表不为空,则:
                //等待拦截器调度中心完成初始化
                checkInterceptorsInitStatus();
    
                if (!interceptorHasInit) {
                     //未初始化,回调告知拦截器初始化太耗时
                    callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
                    return;
                }
    
                LogisticsCenter.executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
                        try {
                            //根据优先级依次调用拦截器的处理程序
                            _execute(0, interceptorCounter, postcard);
                            interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
                            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((Throwable) postcard.getTag());
                            } 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 _execute(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();
                        _execute(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 execute over with fatal exception.
                        //被拦截器拦截,并结束拦截流程
                        postcard.setTag(null == exception ? new HandlerException("No message.") : exception);    // save the exception message for backup.
                        counter.cancel();
                        // Be attention, maybe the thread in callback has been changed,
                        // then the catch block(L207) will be invalid.
                        // The worst is the thread changed to main thread, then the app will be crash, if you throw this exception!
    //                    if (!Looper.getMainLooper().equals(Looper.myLooper())) {    // You shouldn't throw the exception if the thread is main thread.
    //                        throw new HandlerException(exception.getMessage());
    //                    }
                    }
                });
            }
        }
    
        @Override
        public void init(final Context context) {
            //初始化拦截器调度中心服务,是在_Arouter的afterinit中最终调用LogisticsCenter.completion调用的
            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列表
                            Class<? extends IInterceptor> interceptorClass = entry.getValue();
                            try {
                                //根据class反射创建拦截器
                                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;
    
                        logger.info(TAG, "ARouter interceptors init over.");
    
                        synchronized (interceptorInitLock) {
                            //唤醒等待拦截器调度中心初始化锁
                            interceptorInitLock.notifyAll();
                        }
                    }
                }
            });
        }
    
        private static void checkInterceptorsInitStatus() {
          //检测拦截器
            synchronized (interceptorInitLock) {
                while (!interceptorHasInit) {
                    try {
                        //等待拦截器调度中心完成初始化
                        interceptorInitLock.wait(10 * 1000);
                    } catch (InterruptedException e) {
                        throw new HandlerException(TAG + "Interceptor init cost too much time error! reason = [" + e.getMessage() + "]");
                    }
                }
            }
        }
    }
    

    Arouter依赖注入

    我们接着分析依赖注入的源码流程:

    static void inject(Object thiz) {
            //获取Arouter内置的依赖注入服务类
            AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
            if (null != autowiredService) {
                //调用autowire实现自动注入
                autowiredService.autowire(thiz);
            }
        }
    

    Arouter内置了依赖注入服务类AutowiredServiceImpl,我们接着来分析AutowiredServiceImpl:

    @Route(path = "/arouter/service/autowired")
    public class AutowiredServiceImpl implements AutowiredService {
        //lrucache:最近最少使用的依赖注入类
        private LruCache<String, ISyringe> classCache;
        //黑名单列表
        private List<String> blackList;
    
        @Override
        public void init(Context context) {
            //设置最近最少使用LruCache最大容量为50,即最大缓存50个依赖注入类
            classCache = new LruCache<>(50);
            blackList = new ArrayList<>();
        }
    
        @Override
        public void autowire(Object instance) {
            //主动注入
            //调用doInject完成自动注入
            doInject(instance, null);
        }
    
        /**
         * Recursive injection
         *
         * @param instance who call me.
         * @param parent   parent of me.
         */
        private void doInject(Object instance, Class<?> parent) {
            //parant是需要注入的类
            Class<?> clazz = null == parent ? instance.getClass() : parent;
            
            //根据类名获取注射器
            ISyringe syringe = getSyringe(clazz);
            if (null != syringe) {
                //如果注射器不为空,则调用注射器的inject方法,完成对目标类instance中需要依赖注入的字段进行注入赋值
                syringe.inject(instance);
            }
            //获取目标类的父类
            Class<?> superClazz = clazz.getSuperclass();
            // has parent and its not the class of framework.
            if (null != superClazz && !superClazz.getName().startsWith("android")) {
                //继续对目标类的父类完成依赖注入
                doInject(instance, superClazz);
            }
        }
    
        private ISyringe getSyringe(Class<?> clazz) {
            String className = clazz.getName();
    
            try {
                if (!blackList.contains(className)) {
                    //黑名单不含此注射器,则:
                    //从缓存区注射器
                    ISyringe syringeHelper = classCache.get(className);
                    if (null == syringeHelper) {  // No cache.
                        //如果缓存中不存在注册器,则:
                        //通过类名反射创建注射器对象
                        syringeHelper = (ISyringe) Class.forName(clazz.getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
                    }
                    //将注射器将入缓存中
                    classCache.put(className, syringeHelper);
                    //返回注射器
                    return syringeHelper;
                }
            } catch (Exception e) {
                //获取注射器异常,则加入黑名单
                blackList.add(className);    // This instance need not autowired.
            }
    
            return null;
        }
    }
    

    结合上述源码的分析,我们对Arouter可以做如下概括:
    1、对Arouter初始化时,如果没有使用自动注册插件,则需要执行以下的注册操作:

    • 从apk的dex文件中找出所有的路由组文件RouteRoot、服务类文件Provider、拦截器文件
    • 反射创建这些类,并调用他们的loadInto方法:将路由组放入全局路由组表Warehouse.groupsIndex中、将拦截器放入全局拦截器索引表中、Warehouse.interceptorsIndex中、将服务路由信息放入全局服务索引表Warehouse.providersIndex中。

    2、初始化完成后,导航到拦截器调度中心服务,并完成拦截器调度中心服务的初始化
    3、导航时根据路由路径、路由组生成路由明信片对象,接着调用LogisticsCenter的completion完善路由明信片的信息:

    • 反射创建路由组对象RouteRoot,调用RouteRoot的loadInto方法,将组内的路由都缓存到全局的路由表Warehouse.routes中
    • 从全局路由表Warehouse.routes中获取路由元信息,并设置路由明信片的目标路由class、需要注入的字段列表及其参数值、如果是服务则设置服务并进行初始化

    4、非绿色通道需要调用拦截器调度中心,调度所有的拦截器进行处理,如果不拦截则最终调用最后的导航步骤6
    5、绿色通道直接进入最终的导航步骤6
    6、最后的导航步骤

    • 如果是activity,使用明信片的信息构建目标activity的intent、参数列表、标志位等。进入目标activity之后,如果需要依赖注入,则调用inject方法调用对应的注入辅助类完成对字段的注入赋值
    • 如果是fragment,反射创建fragment,并使用明信片的信息设置参数列表,并返回fragment。进入目标fragment之后,如果需要依赖注入,则调用inject方法调用对应的注入辅助类完成对字段的注入赋值
    • 如果是provider,直接返回明信片中的provider
    • 如果是contentprovider或者boardcast,反射创建contentprovider或者boardcast,然后返回contentprovider或者boardcast

    相关文章

      网友评论

          本文标题:Arouter之API原理解析

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