ARouter 拦截器与路由的实现(源码分析)

编程入门 行业动态 更新时间:2024-10-08 08:26:30

ARouter 拦截器与<a href=https://www.elefans.com/category/jswz/34/1771390.html style=路由的实现(源码分析)"/>

ARouter 拦截器与路由的实现(源码分析)

哈哈哈,之前说的ARouter后续分析来了,我是个老湿人。
由于我们的ARouter是通过注解的方式实现的,所以一上来又是APT那套东西,这次呢就不重点讲这个东西,大概说一下,主要笔者对于那些API也不是很熟,只是知道大概在干什么事。接下来就是正文了。
我们都知道,拦截器需要注解@Interceptor,这个注解的接口如下

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Interceptor {/*** The priority of interceptor, ARouter will be excute them follow the priority.*/int priority();/*** The name of interceptor, may be used to generate javadoc.*/String name() default "Default";
}

priority: 优先级,越小,优先级越高

接下来是拦截器的代码生成,这一步的处理是在InterceptorProcessor中,这个代码就不展开说了,这里面主要做的就是代码生成,之前ARouter依赖注入的代码讲了一下,可以去看看 ,最终生成的代码是如下的:

/*** DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Interceptors$$app implements IInterceptorGroup {@Overridepublic void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {interceptors.put(7, Test1Interceptor.class);}
}

接下来就是本文的重点咯。

初始化:
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);if (hasInit) {_ARouter.afterInit();}_ARouter.logger.info(Consts.TAG, "ARouter init over.");}}

然后我们进入

_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;// It's not a good idea.// if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {//     application.registerActivityLifecycleCallbacks(new AutowiredLifecycleCallback());// }return true;}

然后在进入

LogisticsCenter.init(mContext, executor);

重点来了

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {mContext = context;executor = tpe;try {// These class was generate by arouter-compiler.// 由compiler生成的类,获取报名下面的所有类List<String> classFileNames = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);//for (String className : classFileNames) {if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {// This one of root elements, load root.//加载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//加载providers((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() + "]");}}

这里的流程为:扫描包名下面所有的类—>然后根据前缀来区分类的作用,然后放入到不同的容器中,
这里的容器为Warehouse类里面的一些容器,我们先看看Warehouse这个类

class Warehouse {// Cache route and metasstatic Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();static Map<String, RouteMeta> routes = new HashMap<>();// Cache providerstatic Map<Class, IProvider> providers = new HashMap<>();static Map<String, RouteMeta> providersIndex = new HashMap<>();// Cache interceptorstatic Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");static List<IInterceptor> interceptors = new ArrayList<>();static void clear() {routes.clear();groupsIndex.clear();providers.clear();providersIndex.clear();interceptors.clear();interceptorsIndex.clear();}
}

看到这里就明白了,刚刚那一步的作用就是要把所有的group节点加入到Warehouse.groupsIndex,把所有的拦截器加入到Warehouse.interceptorsIndex,把所有的provider加入到Warehouse.providersIndex

现在回到初始化这里 我们在进入

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

看这个代码

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

我们先看看这个build方法,一步一步点进去,最后看到的代码是

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

他返回了一个 Postcard对象,这个对象很重要,这个对象继承自RouteMeta,他拥有很多属性,比如路由地址,bundle参数等等。

    private RouteType type;         // Type of routeprivate Element rawType;        // Raw type of routeprivate Class<?> destination;   // Destinationprivate String path;            // Path of routeprivate String group;           // Group of routeprivate int priority = -1;      // The smaller the number, the higher the priorityprivate int extra;              // Extra dataprivate Map<String, Integer> paramsType;  // Param typeprivate Uri uri;private Object tag;             // A tag prepare for some thing wrong.private Bundle mBundle;         // Data to transformprivate int flags = -1;         // Flags of routeprivate int timeout = 300;      // Navigation timeout, TimeUnit.Secondprivate IProvider provider;     // It will be set value, if this postcard was     provider.private boolean greenChannel;private SerializationService serializationService;// Animationprivate Bundle optionsCompat;    // The transition animation of activityprivate int enterAnim;private int exitAnim;

好, 回到刚才的代码

interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();

我们进入navigation()方法

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {try {LogisticsCenterpletion(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);} 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*/@Overridepublic void onContinue(Postcard postcard) {_navigation(context, postcard, requestCode, callback);}/*** Interrupt process, pipeline will be destory when this method called.** @param exception Reson of interrupt.*/@Overridepublic 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;}

第一步我们进入

LogisticsCenterpletion(postcard);

这段代码很简单,看注释就好了

public synchronized static void completion(Postcard postcard) {if (null == postcard) {throw new NoRouteFoundException(TAG + "No postcard!");}// 如果路由的路径没找到,那么可能是这个group下的路径还没有加载// 首先获取到group,然后将当前group下的所有path加入到仓库的routes 这个map中 (Warehouse.routes)// 然后从仓库的groupsIndex这个map中删掉这个group// 然后重新加载 在执行一次本方法// 如果已经加载了则执行elseRouteMeta 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);// TODO: 2017/10/26  不懂为什么需要删掉这个groupWarehouse.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);   // Reload}} else {//往postcard里面填充信息//设置跳转的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.//解析路径上的参数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 @Paramfor (Map.Entry<String, Integer> params : paramsType.entrySet()) {setValue(postcard,params.getValue(),params.getKey(),resultMap.get(params.getKey()));}// Save params name which need autoinject.postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));}// Save raw uripostcard.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 be implememt IProviderClass<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();IProvider instance = Warehouse.providers.get(providerMeta);if (null == instance) { // There's no instance of this providerIProvider 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);//provider也不需要拦截器postcard.greenChannel();    // Provider should skip all of interceptorsbreak;case FRAGMENT://设置绿色通道为true,fragment不需要拦截器postcard.greenChannel();    // Fragment needn't interceptorsdefault:break;}}}

看到初始化拦截器这里

 @Overridepublic void init(final Context context) {LogisticsCenter.executor.execute(new Runnable() {@Overridepublic void run() {if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {Class<? extends IInterceptor> interceptorClass = entry.getValue();try {IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();//初始化iInterceptor.init(context);Warehouse.interceptors.add(iInterceptor);} catch (Exception ex) {throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");}}interceptorHasInit = true;logger.info(TAG, "ARouter interceptors init over.");synchronized (interceptorInitLock) {interceptorInitLock.notifyAll();}}}});}

接着LogisticsCenterpletion(postcard);继续执行下去
然后由于provider是绿色通道,所以直接执行_navigation(context, postcard, requestCode, callback);
然后返回,这样初始化流程中拦截器就初始完成了。

接下来就是路由和拦截器拦截了
现在就不从最开始讲了,读者可以一步一步跳进去,然后跟着走。
请读者先跳到

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {try {LogisticsCenterpletion(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);} 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*/@Overridepublic void onContinue(Postcard postcard) {_navigation(context, postcard, requestCode, callback);}/*** Interrupt process, pipeline will be destory when this method called.** @param exception Reson of interrupt.*/@Overridepublic 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;}

我们直接看到这段代码的
if (!postcard.isGreenChannel())
一般来说我们的activity没有设置成绿色通道,所以会进入这个条件语句,我们进入 interceptorService.doInterceptions方法

我们看到这段代码

LogisticsCenter.executor.execute(new Runnable() {@Overridepublic void run() {CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());try {_excute(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(new HandlerException(postcard.getTag().toString()));} else {callback.onContinue(postcard);}} catch (Exception e) {callback.onInterrupt(e);}}});

在这里面最关键的就是一个CancelableCountDownLatch类,这个类是继承于CountDownLatch,在异步线程中,每执行一次_excute()方法,就countDown一次,这样就能保证在这个线程中,将所有的拦截器都执行一次。当所有的拦截器都通过之后,会调用 onContinue回调,在回调中会执行

 @Overridepublic void onContinue(Postcard postcard) {_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 intentfinal 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() {@Overridepublic void run() {if (requestCode > 0) {  // Need start for resultActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());} else {ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());}if ((0 != postcard.getEnterAnim() || 0 != 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: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;}

这里就是我们的跳转处理了。

关于provider那一块没有怎么讲,目前笔者感觉用的不多。大家需要就自己看吧。

更多推荐

ARouter 拦截器与路由的实现(源码分析)

本文发布于:2024-02-11 22:35:21,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1683974.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:路由   源码   拦截器   ARouter

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!