Arouter原理详解

对于组件化这个东西这里就不进行讲解了,组件化本身的目的是为了解耦,各个组件负责各自的功能,然后把各个组件组合起来就是一个完整的项目了,组合起来的时候,就会涉及到组件间的通讯问题,比如这个module的Activity调用另外一个module的activity,如果是直接调用,那显然他们之间就有了耦合了,为了组件间的解耦,这个时候就可以用到Arouter了,关于Arouter的使用这里可以去Git上看看,这里就先给个地址了:Arouter git 官方使用讲解,要了解Arouter,可以从他的两个注解开始:

  1. Route注解;
  2. Interceptor注解;

Arouter的服务注入这里就不讲解了。

Arouter 注解

对于Route和Interceptor注解,当我们在类上使用这两个注解时,rebuild下工程,会在/build/generated/source/apt/debug/com/aliababa.android.arouter.routes目录下生成对应的class文件,如下:
Arouter生成的文件
这里先来看下ARouter$ $Root$$main这个类:

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

这里的main和welcom其实是Arouter的一个分组,这里map存放的key就是这个分组,根据这个分组按需来进行的加载的,这里再看下ARouter$ $Group$$main:

public class ARouter$$Group$$main implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/main/main", RouteMeta.build(RouteType.ACTIVITY, MainActivity.class, "/main/main", "main", null, -1, -2147483648));
  }
}

这里也是通过一个map进行存放的,这里存放的key值是注解Route的path的值,value存放的是相关类的一些信息,根据这里信息就可以找到对应的类,通过这两个map集合,就可以实现按组按需进行加载,关于加载的逻辑后面会进行讲解,这里再来看下interceptor生成的class:

public class ARouter$$Interceptors$$arouterlibrary implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    interceptors.put(7, ArouterIntercept.class);
    interceptors.put(8, ArouterIntercept1.class);
  }
}

注意看这里的key值,是数值7和8,为什么是这两个数值呢?这里其实很好理解,可以先看下在代码中的注解:

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

    }

    @Override
    public void init(Context context) {

    }
}

发现什么了,没错,key值其实就是这里priority的值,注意这个值是不能重复得,否则是会编译报错的,这个值是什么意思呢?顾名思义就是优先级了,看了这些生成的类后,接下来看看在代码中的一个执行流程了。

Arouter初始化流程

首先是Arouter的初始化,一般在Application的onCreate()方法中调用ARouter.init(this),先来看看在这个方法中执行了什么:

    public static void init(Application application) {
        if (!hasInit) {
            logger = _ARouter.logger;
            _ARouter.logger.info(Consts.TAG, "ARouter init start.");
            hasInit = _ARouter.init(application);//1

            if (hasInit) {
                _ARouter.afterInit();//2 初始化拦截器
            }

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

注意这里有个hasInit,说明这里只能被调用一次,这里主要是执行两点,一是获取注解生成的类,并读取到集合中,二是在_ARouter.afterInit()中初始化一个服务,这个服务主要是处理拦截器的,后面在说了,这里先进_ARouter.init(application)里来看看:

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

代码很简单,这里主要去看下LogisticsCenter.init(mContext, executor),这里才是实现初始化的主要逻辑:

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

        try {
            long startInit = System.currentTimeMillis();
            //billy.qi modified at 2017-12-06
            //load by plugin first
            loadRouterMap();//主要是置位registerByPlugin为false
            if (registerByPlugin) {
                logger.info(TAG, "Load router map by arouter-auto-register plugin.");
            } else {
                Set<String> routerMap;

                // It will rebuild router map every times when debuggable.
                //如果是开启了debuggable或者是一个新版本,就会先去解析指定包下的类,这里指定的包就是上面
                //说到的生成的类
                if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
                    logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
                    // These class was generated by arouter-compiler.
                    //这个方法主要就是去解析类,然后存放到set集合中
                    routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
                    //不为null就说明有生成的类,那么就保存起来,方便下次使用
                    if (!routerMap.isEmpty()) {
                        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.
                        //这里是将分组的类加载到内存中来
                        ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                    } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_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)) {
                        // Load providerIndex
                        //这里是加载服务
                        ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                    }
                }
            }

            logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");

            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() + "]");
        }
    }

对于上面的讲解已经在方法中注明,主要的还是要明白for循环里面做了什么事,这里注意下这几个存数据的集合,后面的流程会有用到,到这里就算初始化完成了。

Arouter 路由流程

先来看下Arouter路由的用法:

ARouter.getInstance().build(RouterProtocol.MEDIARESOURCE_MAIN).navigation();

这里传入的是Route注解的路线,build创建的是一个Postcard对象,传进去的路线就是存放在这个对象里,如果没有对路线进行分组,那么这里面回去第一个字符串作为组名,这个对象里存放的是一些需要路由的信息,比如是否启用拦截器、启动activity的动画等,调用的navigation()方法最终都会调用的到下面这个方法:

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

这里有一个回调,在这个回调里可以处理路由目标没有找到,路由目标找到,路由完成的一些处理,可以根据需要进行处理,接下来调用的是Arouter的navigation()方法:

public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
        return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
    }

接着往下调用_Arouter的方法,在这里才是处理路由跳转的主要逻辑的:

    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    //对路由进行预处理,前提是实现 PretreatmentService 接口,并加上一个Path内容任意的注解即可
        PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
        if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
            // Pretreatment failed, navigation canceled.
            return null;
        }

        try {
        //基于postcard中的path去获取需要路由到哪个类
            LogisticsCenter.completion(postcard);
        } catch (NoRouteFoundException ex) {
            logger.warning(Consts.TAG, ex.getMessage());

            if (debuggable()) {
                // Show friendly tips for user.
                runInMainThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(mContext, "There's no route matched!\n" +
                                " Path = [" + postcard.getPath() + "]\n" +
                                " Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
                    }
                });
            }
			
            if (null != callback) {
            	//设置了callback,当没找到路由目标时,会被调用
                callback.onLost(postcard);
            } else {
                // No callback for this invoke, then we use the global degrade service.
                //如果没有设置callback,并且定义了一个降级服务,那么就会调用这个降级服务
                //这个降级服务实现DegradeService接口,并加上一个Path内容任意的注解即可
                DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
                if (null != degradeService) {
                    degradeService.onLost(context, postcard);
                }
            }

            return null;
        }

        if (null != callback) {
        	//路由目标找到,会调用到回调的onFound()方法
            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(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;
    }

这里有两个方法是需要重点关注的:

  1. LogisticsCenter.completion(postcard);
  2. _navigation(context, postcard, requestCode, callback);
    这里先来说下 _navigation(context, postcard, requestCode, callback);这个方法里面实现的是路由到目标,先来看看:
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:
                // 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);
                }

                // Set Actions
                String action = postcard.getAction();
                if (!TextUtils.isEmpty(action)) {
                    intent.setAction(action);
                }

                // Navigation in main looper.
                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;
    }

这个方法里面实现的逻辑还是比较简单的,基本看下都能明白是什么意思,这里注意下TYPE是ACTIVITY的startActivity(requestCode, currentContext, intent, postcard, callback)方法:

private void startActivity(int requestCode, Context currentContext, Intent intent, Postcard postcard, NavigationCallback callback) {
        if (requestCode >= 0) {  // Need start for result
            if (currentContext instanceof Activity) {
                ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
            } else {
                logger.warning(Consts.TAG, "Must use [navigation(activity, ...)] to support [startActivityForResult]");
            }
        } 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);
        }
    }

在这里添加了启动activity的执行动画,以后回调方法的onArrival()方法,至此,打开activity的整个流程就梳理完了。这里还需要再来看下LogisticsCenter.completion(postcard):

    public synchronized static void completion(Postcard postcard) {
        if (null == postcard) {
            throw new NoRouteFoundException(TAG + "No postcard!");
        }
		//先根据路径去拿到对应的组内的路由目标,如果没有找到,那么就会先去加载对应的组
        RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
        if (null == routeMeta) {    // Maybe its does't exist, or didn't load.
        	//先获取组
            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 {
                // Load route and cache it into memory, then delete from metas.
                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() + "]");
                }
				//再一次调用这个方法,就会执行到下面的else方法了
                completion(postcard);   // Reload
            }
        } else {
        	//这里主要是对postcard设置数据
            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.
                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;
            }
        }
    }

这里寻找路由目标主要体现在的一个按组加载,如果是已经加载的组,那么就直接取出,如果加载过,那么在第一次使用这个组内的元素时,就会去加载这个组内的所有元素,之后直接用就可以了。这里需要注意一个点,就是这个@Route里的path,填写路径是要以"/"开头,要不然不会生成对应的类,路由的时候就会出错

@Autowired
@Autowired主要用于注入,这里的注入主要有两种用法,一是直接从Intent中拿数据,这也是网上说的比较多的,这里就不多说了,二是注入我们所需的对象,如何去注入对象呢?主要有四个步骤:

  1. 实现IProvider接口,里面有个init()方法,主要是用于做初始化操作,替代了构造函数;
  2. 使用@Route注解这个类,path=“/xxx/xxx”;
  3. 在需要注入这个类的地方,在这个类的字段属性上使用@Autowired(path="/xxx/xxx");@Autowired(name = "/message/person") public IMessage message;
  4. 在使用这个类对象之前,调用ARouter.getInstance().inject(this),这样就会创建这个类对象
    这样这个对象就算创建完成了,,这里同样有个需要注意的地方,这里注入的这个对象是一个单例对象,最后再看下通过@Autowired注解会生成的类:
public class SecondActivity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    SecondActivity substitute = (SecondActivity)target;
    substitute.message = (IMessage)ARouter.getInstance().build("/message/person").navigation();
    substitute.name = substitute.getIntent().getStringExtra("name");
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值