| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> ARouter源码详解,零基础学习android编程 -> 正文阅读 |
|
[移动开发]ARouter源码详解,零基础学习android编程 |
ARouter.getInstance().build(RoutePath.USER_HOME).navigation() 复制代码
/**
*/ 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) { //用于路径替换,这对于某些需要控制页面跳转流程的场景比较有用 //例如,如果某个页面需要登录才可以展示的话 //就可以通过 PathReplaceService 将 path 替换 loginPagePath path = pService.forString(path); } //使用字符串 path 包含的第一个单词作为 group return build(path, extractGroup(path)); } } /**
*/ 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); } } 复制代码 返回的 public final class Postcard extends RouteMeta { // Base private Uri uri; private Object tag; // A tag prepare for some thing wrong. private Bundle mBundle; // Data to transform private int flags = -1; // Flags of route private int timeout = 300; // Navigation timeout, TimeUnit.Second private IProvider provider; // It will be set value, if this postcard was provider. private boolean greenChannel; private SerializationService serializationService; } 复制代码
final class _ARouter { /**
*/ 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. //用于执行跳转前的预处理操作,可以通过 onPretreatment 方法的返回值决定是否取消跳转 return null; } try { 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.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() { /**
*/ @Override public void onContinue(Postcard postcard) { //拦截器允许跳转 _navigation(context, 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(context, postcard, requestCode, callback); } return null; } //由于本例子的目标页面是 Activity,所以只看 ACTIVITY 即可 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 //Destination 就是指向目标 Activity 的 class 对象 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; ··· //省略其它类型判断 } return null; } } 复制代码
/**
*/ 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) { //为 null 说明目标类不存在或者是该 group 还未加载过 Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // Load route meta. if (null == groupMeta) { //groupMeta 为 null,说明 postcard 的 path 对应的 group 不存在,抛出异常 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())); } //会执行到这里,说明此 group 还未加载过,那么就来反射加载 group 对应的所有 path 信息 //获取后就保存到 Warehouse.routes IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance(); iGroupInstance.loadInto(Warehouse.routes); //移除此 group 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); // Reload } } else { //拿到详细的路由信息了,将这些信息存到 postcard 中 postcard.setDestination(routeMeta.getDestination()); postcard.setType(routeMeta.getType()); postcard.setPriority(routeMeta.getPriority()); postcard.setExtra(routeMeta.getExtra()); //省略一些和本例子无关的代码 ··· } } 复制代码 五、跳转到 Activity 并注入参数ARouter 也支持在跳转到 Activity 的同时向目标页面自动注入参数 在跳转的时候指定要携带的键值对参数: ARouter.getInstance().build(RoutePath.USER_HOME) .withLong(RoutePath.USER_HOME_PARAMETER_ID, 20) .withString(RoutePath.USER_HOME_PARAMETER_NAME, “leavesC”) .navigation() object RoutePath { const val USER_HOME = “/account/userHome” const val USER_HOME_PARAMETER_ID = “userHomeId” const val USER_HOME_PARAMETER_NAME = “userName” } 复制代码 在目标页面通过 这样,在我们调用 package github.leavesc.user /**
*/ @Route(path = RoutePath.USER_HOME) class UserHomeActivity : AppCompatActivity() { @Autowired(name = RoutePath.USER_HOME_PARAMETER_ID) @JvmField var userId: Long = 0 @Autowired @JvmField var userName = “” override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_user_home) ARouter.getInstance().inject(this) tv_hint.text = “$userId $userName” } } 复制代码 ARouter 实现参数自动注入也需要依靠注解处理器生成的辅助文件来实现,即会生成以下的辅助代码: package github.leavesc.user; /**
public class UserHomeActivity A R o u t e r ARouter ARouterAutowired implements ISyringe { //用于实现序列化和反序列化 private SerializationService serializationService; @Override public void inject(Object target) { serializationService = ARouter.getInstance().navigation(SerializationService.class); UserHomeActivity substitute = (UserHomeActivity)target; substitute.userId = substitute.getIntent().getLongExtra(“userHomeId”, substitute.userId); substitute.userName = substitute.getIntent().getStringExtra(“userName”); } } 复制代码 因为在跳转到 Activity 时携带的参数也是需要放到 现在来看下 ARouter 是如何实现参数自动注入的,其起始方法就是: final class _ARouter { static void inject(Object thiz) { AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation()); if (null != autowiredService) { autowiredService.autowire(thiz); } } } 复制代码 ARouter 通过控制反转的方式拿到 由于生成的参数注入辅助类的类名具有固定的包名和类名,即包名和目标类所在包名一致,类名是目标类类名+ @Route(path = “/arouter/service/autowired”) public class AutowiredServiceImpl implements AutowiredService { private LruCache<String, ISyringe> classCache; private List blackList; @Override public void init(Context context) { classCache = new LruCache<>(66); blackList = new ArrayList<>(); } @Override public void autowire(Object instance) { String className = instance.getClass().getName(); try { //如果在白名单中了的话,那么就不再执行参数注入 if (!blackList.contains(className)) { ISyringe autowiredHelper = classCache.get(className); if (null == autowiredHelper) { // No cache. autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance(); } //完成参数注入 autowiredHelper.inject(instance); //缓存起来,避免重复反射 classCache.put(className, autowiredHelper); } } catch (Exception ex) { //如果参数注入过程抛出异常,那么就将其加入白名单中 blackList.add(className); // This instance need not autowired. } } } 复制代码 六、控制反转上一节所讲的跳转到 Activity 并自动注入参数属于依赖注入的一种,ARouter 同时也支持控制反转:通过接口来获取其实现类实例 例如,假设存在一个 /**
*/ interface ISayHelloService : IProvider { fun sayHello() } @Route(path = RoutePath.SERVICE_SAY_HELLO) class SayHelloService : ISayHelloService { override fun init(context: Context) { } override fun sayHello() { Log.e(“SayHelloService”, “$this sayHello”) } } 复制代码 在使用的时候直接传递 ARouter.getInstance().navigation(ISayHelloService::class.java).sayHello() 复制代码 和实现 Activity 跳转的时候一样,ARouter 也会自动生成以下几个文件,包含了路由表的映射关系 package com.alibaba.android.arouter.routes; /**
public class ARouter G r o u p Group Groupaccount implements IRouteGroup { @Override public void loadInto(Map<String, RouteMeta> atlas) { atlas.put("/account/sayHelloService", RouteMeta.build(RouteType.PROVIDER, SayHelloService.class, “/account/sayhelloservice”, “account”, null, -1, -2147483648)); } } /**
public class ARouter P r o v i d e r s Providers Providersuser implements IProviderGroup { @Override public void loadInto(Map<String, RouteMeta> providers) { providers.put(“github.leavesc.user.ISayHelloService”, RouteMeta.build(RouteType.PROVIDER, SayHelloService.class, “/account/sayHelloService”, “account”, null, -1, -2147483648)); } } /**
public class ARouter R o o t Root Rootuser implements IRouteRoot { @Override public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) { routes.put(“account”, ARouter G r o u p Group Groupaccount.class); } } 复制代码 这里再来看下其具体的实现原理 在讲初始化流程的时候有讲到, Warehouse.groupsIndex:
Warehouse.providersIndex:
protected T navigation(Class<? extends T> service) { try { //从 Warehouse.providersIndex 取值拿到 RouteMeta 中存储的 path 和 group 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; } //重点 LogisticsCenter.completion(postcard); return (T) postcard.getProvider(); } catch (NoRouteFoundException ex) { logger.warning(Consts.TAG, ex.getMessage()); return null; } } 复制代码
/**
*/ public synchronized static void completion(Postcard postcard) { … //省略之前已经讲解过的代码 RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath()); switch (routeMeta.getType()) { case PROVIDER: // if the route is provider, should find its instance // Its provider, so it must implement IProvider //拿到 SayHelloService Class 对象 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 //instance 等于 null 说明是第一次取值 //那么就通过反射构建 SayHelloService 对象,然后将之缓存到 Warehouse.providers 中 //所以通过控制反转获取的对象在应用的整个生命周期内只会有一个实例 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; } } 复制代码 七、拦截器ARouter 的拦截器对于某些需要控制页面跳转流程的业务逻辑来说是十分有用的功能。例如,用户如果要跳转到个人资料页面时,我们就可以通过拦截器来判断用户是否处于已登录状态,还未登录的话就可以拦截该请求,然后自动为用户打开登录页面 我们可以同时设定多个拦截器,每个拦截器设定不同的优先级 /**
*/ @Interceptor(priority = 100, name = “啥也不做的拦截器”) class NothingInterceptor : IInterceptor { override fun init(context: Context) { } override fun process(postcard: Postcard, callback: InterceptorCallback) { //不拦截,任其跳转 callback.onContinue(postcard) } } @Interceptor(priority = 200, name = “登陆拦截器”) class LoginInterceptor : IInterceptor { override fun init(context: Context) { } override fun process(postcard: Postcard, callback: InterceptorCallback) { if (postcard.path == RoutePath.USER_HOME) { //拦截 callback.onInterrupt(null) //跳转到登陆页 ARouter.getInstance().build(RoutePath.USER_LOGIN).navigation() } else { //不拦截,任其跳转 callback.onContinue(postcard) } } } 复制代码 这样,当我们执行 来看下拦截器是如何实现的 对于以上的两个拦截器,会生成以下的辅助文件。辅助文件会拿到所有我们自定义的拦截器实现类并根据优先级高低存到 Map 中 package com.alibaba.android.arouter.routes; /**
public class ARouter I n t e r c e p t o r s Interceptors Interceptorsuser implements IInterceptorGroup { @Override public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) { interceptors.put(100, NothingInterceptor.class); interceptors.put(200, LoginInterceptor.class); } } 复制代码 而这些拦截器一样是会在初始化的时候,通过 /**
*/ public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException { ··· 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); } } ··· } 复制代码 然后,在 final class _ARouter { /**
*/ protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) { ··· 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(context, 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(context, postcard, requestCode, callback); } return null; } } 复制代码
@Route(path = “/arouter/service/interceptor”) public class InterceptorServiceImpl implements InterceptorService { private static boolean interceptorHasInit; private static final Object interceptorInitLock = new Object(); @Override public void init(final Context context) { 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<? 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(); } } } }); } @Override public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) { if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) { 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 { _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. //大于 0 说明此次请求被某个拦截器拦截了,走失败流程 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); } } }); } else { callback.onContinue(postcard); } } /**
*/ private static void _excute(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(); _excute(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 excute over with fatal exception. postcard.setTag(null == exception ? new HandlerException(“No message.”) : exception.getMessage()); // 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()); // } } }); } } 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 中起到了很大的作用,依靠注解处理器生成的辅助文件,ARouter 才能完成参数自动注入等功能。这里就再来介绍下 ARouter 关于注解处理器的实现原理 APT(Annotation Processing Tool) 即注解处理器,是一种注解处理工具,用来在编译期扫描和处理注解,通过注解来生成 Java 文件。即以注解作为桥梁,通过预先规定好的代码生成规则来自动生成 Java 文件。此类注解框架的代表有 ButterKnife、Dragger2、EventBus 等 Java API 已经提供了扫描源码并解析注解的框架,开发者可以通过继承 AbstractProcessor 类来实现自己的注解解析逻辑。APT 的原理就是在注解了某些代码元素(如字段、函数、类等)后,在编译时编译器会检查 AbstractProcessor 的子类,并且自动调用其 process() 方法,然后将添加了指定注解的所有代码元素作为参数传递给该方法,开发者再根据注解元素在编译期输出对应的 Java 代码 关于 APT 技术的原理和应用可以看这篇文章:Android APT 实例讲解 ARouter 源码中和注解处理器相关的 module 有两个:
这里主要来看 package github.leavesc.user /**
*/ @Interceptor(priority = 100, name = “啥也不做的拦截器”) class NothingInterceptor : IInterceptor { override fun init(context: Context) { } override fun process(postcard: Postcard, callback: InterceptorCallback) { //不拦截,任其跳转 callback.onContinue(postcard) } } 复制代码 生成的辅助文件: package com.alibaba.android.arouter.routes; import com.alibaba.android.arouter.facade.template.IInterceptor; import com.alibaba.android.arouter.facade.template.IInterceptorGroup; import github.leavesc.user.NothingInterceptor; import java.lang.Class; import java.lang.Integer; import java.lang.Override; import java.util.Map; /**
public class ARouter I n t e r c e p t o r s Interceptors Interceptorsuser implements IInterceptorGroup { @Override public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) { interceptors.put(100, NothingInterceptor.class); } } 复制代码 那么,生成的辅助文件我们就要包含以下几个元素:
如果通过硬编码的形式,即通过拼接字符串的方式来生成以上代码也是可以的,但是这样会使得代码不好维护且可读性很低,所以 ARouter 是通过 拦截器对应的
@AutoService(Processor.class) @SupportedAnnotationTypes(ANNOTATION_TYPE_INTECEPTOR) public class InterceptorProcessor extends BaseProcessor { //用于保存拦截器,按照优先级高低进行排序 private Map<Integer, Element> interceptors = new TreeMap<>(); private TypeMirror iInterceptor = null; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); iInterceptor = elementUtils.getTypeElement(Consts.IINTERCEPTOR).asType(); logger.info(">>> InterceptorProcessor init. <<<"); } /**
*/ @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (CollectionUtils.isNotEmpty(annotations)) { //拿到所有使用了 @Interceptor 进行修饰的代码元素 Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Interceptor.class); try { parseInterceptors(elements); } catch (Exception e) { logger.error(e); } return true; } return false; } /**
*/ private void parseInterceptors(Set<? extends Element> elements) throws IOException { if (CollectionUtils.isNotEmpty(elements)) { logger.info(">>> Found interceptors, size is " + elements.size() + " <<<"); // Verify and cache, sort incidentally. for (Element element : elements) { //判断使用了 @Interceptor 进行修饰的代码元素是否同时实现了 com.alibaba.android.arouter.facade.template.IInterceptor 这个接口 //两者缺一不可 if (verify(element)) { // Check the interceptor meta logger.info("A interceptor verify over, its " + element.asType()); |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 7:47:59- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |