携手创造,共同成长!这是我参与「日新方案 8 月更文应战」的第7天,点击检查活动详情>>
Hi,我是小余。
本文已收录到GitHub Androider-Planet中。这儿有 Android 进阶成长常识体系,重视大众号 [小余的自习室] ,在成功的路上不迷路!
前语
最近组里需求进行组件化结构的改造,用到了ARouter这个开源结构,为了更好的对项目进行改造,笔者花了一些时间去了解了下ARouter
ARouter
是阿里巴巴团队在17年头发布的一款针对组件化模块之间无触摸通讯的一个开源结构,经过多个版别的迭代,现在现已非常成熟了。
ARouter
首要效果:组件间通讯,组件解耦,路由跳转,涉及到咱们常用的Activity,Provider,Fragment等多个场景的跳转
接下来笔者会以几个阶段来对Arouter
进行解说:
- Android开源系列-组件化结构Arouter-(一)运用办法详解
- Android开源系列-组件化结构Arouter-(二)深度原理解析
- Android开源系列-组件化结构Arouter-(三)APT技能详解
- Android开源系列-组件化结构Arouter-(四)AGP插件详解
这篇文章咱们来解说下:Arouter的根本原理
1.ARouter认知
首先咱们从命名来看:ARouter翻译过来便是一个路由器
。
官方界说
:
一个用于协助 Android App 进行组件化改造的结构 —— 支持模块间的路由、通讯、解耦
那么什么是路由呢? 简略理解便是:一个公共渠道转发系统
工作办法:
- 1.注册服务:将咱们需求对外露出的页面或许服务注册到ARouter公共渠道中
- 2.调用服务:调用ARouter的接口,传入地址和参数,ARouter解析传入的地址和参数转发到对应的服务中
经过ARouter形成了一个无触摸解耦的调用进程
2.ARouter架构解析
咱们来看下ARouter
的源码架构:
- app:是ARouter提供的一个测试Demo
- arouter-annotation:这个lib模块中声明晰许多注解信息和一些枚举类
- arouter-api:ARouter的中心api,转换进程的中心操作都在这个模块里边
- arouter-compiler:APT处理器,主动生成路由表的进程便是在这儿边完结的
- arouter-gradle-plugin:这是一个编译期运用的Plugin插件,首要效果是用于编译器主动加载路由表,节省应用的发动时间。
3.原理解说
这儿咱们不会一开端就大篇幅对源码进行解说: 咱们先来介绍ARouter中的几个重要概念:有了这几个概念,后边在去看源码就会轻松多了
前置根底概念:
概念1:PostCard
(明信片)
既然是明信片要将函件寄到意图人的手上就至少需求:收件人的姓名和地址,寄件人以及电话和地址等
ARouter便是运用PostCard
这个类来存储寄件人和收件人信息的。
public final class Postcard extends RouteMeta {
// Base
private Uri uri; //假如运用Uri办法建议luyou
private Object tag; // A tag prepare for some thing wrong. inner params, DO NOT USE!
private Bundle mBundle; // 需求传递的参数运用bundle存储
private int flags = 0; // 发动Activity的标志:如NEW_FALG
private int timeout = 300; // 路由超时
private IProvider provider; // 运用IProvider的办法跳转
private boolean greenChannel; //绿色通道,能够不经过阻拦器
private SerializationService serializationService; //序列化服务serializationService:需求传递Object自界说类型目标,就需求完结这个服务
private Context context; // May application or activity, check instance type before use it.
private String action; //Activity跳转的Action
// Animation
private Bundle optionsCompat; // The transition animation of activity
private int enterAnim = -1;
private int exitAnim = -1;
...
}
PostCard
承继了RouteMeta
:
public class RouteMeta {
private RouteType type; // 路由类型:如Activity,Fragment,Provider等
private Element rawType; // 路由原始类型,在编译时用来判别
private Class<?> destination; // 意图Class目标
private String path; // 路由注册的path
private String group; // 路由注册的group分组
private int priority = -1; // 路由履行优先级,priority越低,优先级越高,这个一般在阻拦器中运用
private int extra; // Extra data
private Map<String, Integer> paramsType; // 参数类型,例如activity中运用@Autowired的参数类型
private String name; //路由名字,用于生成javadoc
private Map<String, Autowired> injectConfig; // 参数配置(对应paramsType).
}
RouteMeta
:首要存储的是一些意图目标的信息,这些目标是在路由注册的时分才会生成。
概念2:Interceptor
阻拦器
了解OkHttp
的都知道,其内部调用进程便是运用的阻拦器形式,每个阻拦器履行的对应的使命。
而ARouter
中也是如此,一切的路由调用进程在到达意图地前都会先经过自界说的一系列阻拦器,完结一些AOP切面
编程。
public interface IInterceptor extends IProvider {
/**
* The operation of this interceptor.
*
* @param postcard meta
* @param callback cb
*/
void process(Postcard postcard, InterceptorCallback callback);
}
IInterceptor
是一个接口,承继了IProvider
,所以其也是一个服务类型
只需求完结process
办法就能够完结阻拦操作。
概念3:greenChannel
:绿色通道
设置了绿色通道的跳转进程,能够不经过阻拦器
概念4:Warehouse
:路由库房
Warehouse意为库房,用于存放被 @Route、@Interceptor
注释的 路由相关的信息,也便是咱们重视的destination
等信息
举个例子:
moduleB建议路由跳转到moduleA的activity,moduleB没有依靠moduleA,只是在moduleA的activity上增加了@Route注解。 因为进行activity跳转需求目标Activity的class目标来构建intent,所以必须有一个中间人,把途径”/test/activity”翻译成Activity的class目标,然后moduleB才能完结跳转。(因此在ARouter的运用中 moduleA、moduleB 都是需求依靠 arouter-api的)
这个中间人那便是ARouter
了,而这个翻译工所效果到的词典便是Warehouse
,它存着一切路由信息。
class Warehouse {
//一切IRouteGroup完结类的class目标,是在ARouter初始化中赋值,key是path榜首级
//(IRouteGroup完结类是编译时生成,代表一个组,即path榜首级相同的一切路由,包含Activity和Provider服务)
static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
//一切路由元信息,是在completion中赋值,key是path
//初次进行某个路由时就会加载整个group的路由,即IRouteGroup完结类中一切路由信息。包含Activity和Provider服务
static Map<String, RouteMeta> routes = new HashMap<>();
//一切服务provider实例,在completion中赋值,key是IProvider完结类的class
static Map<Class, IProvider> providers = new HashMap<>();
//一切provider服务的元信息(完结类的class目标),是在ARouter初始化中赋值,key是IProvider完结类的全类名。
//首要用于运用IProvider完结类的class建议的获取服务的路由,例如ARouter.getInstance().navigation(HelloService.class)
static Map<String, RouteMeta> providersIndex = new HashMap<>();
//一切阻拦器完结类的class目标,是在ARouter初始化时收集到,key是优先级
static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("...");
//一切阻拦器实例,是在ARouter初始化完结后当即创建
static List<IInterceptor> interceptors = new ArrayList<>();
...
}
Warehouse存了哪些信息呢?
- groupsIndex:存储一切路由组元信息:
key:group的称号
value:路由组的模块类class类:
赋值机遇:初始化的时分
- routes:存储一切路由元信息。切记和上面路由组分隔,路由是单个路由,路由组是一批次路由
key:路由的path
value:路由元信息
赋值机遇:LogisticsCenter.completion中赋值
补白:初次进行某个路由时就会加载整个group的路由,即IRouteGroup完结类中一切路由信息。包含Activity和Provider服务
- providers:存储一切服务provider实例。
key:IProvider完结类的class
value:IProvider实例
赋值机遇:在LogisticsCenter.completion中赋值
- providersIndex:存储一切provider服务元信息(完结类的class目标)。
key:IProvider完结类的全类名
value:provider服务元信息
赋值机遇:ARouter初始化中赋值。
补白:用于运用IProvider完结类class建议的获取服务的路由,例如ARouter.getInstance().navigation(HelloService.class)
- interceptorsIndex:存储一切阻拦器完结类class目标。
key:优先级
value:一切阻拦器完结类class目标
赋值机遇:是在ARouter初始化时收集到
- interceptors,一切阻拦器实例。是在ARouter初始化完结后当即创建
其间groupsIndex、providersIndex、interceptorsIndex是ARouter初始化时就预备好的根底信息,为业务中随时建议路由操作(Activity跳转、服务获取、阻拦器处理)做好预备。
概念5:APT
注解处理器
ARouter运用注解处理器,主动生成路由协助类: 咱们运用ARouter编译后,会在对应模块下主动生成以下类: 这些类的生成规则都是经过APT在编译器主动生成的,关于APT在ARouter中的运用办法,后边会独自拿一节出来解说:
- Android开源系列-组件化结构Arouter-(三)APT技能详解
概念6:AGP
插件
ARouter运用了一个可选插件:”com.alibaba:arouter-register:1.0.2″ 运用这个插件能够在编译器在包中主动检测以及加载路由表信息,而不需求在运行发动阶段再运用包名去dex文件中加载,提高app发动功率 关于这块的,后边会在:
- Android开源系列-组件化结构Arouter-(四)AGP插件详解
有了以上几个概念做根底现在咱们再到源码中去看看ARouter是怎么跨模块运行起来的
源码剖析:
首先咱们来看路由进程:
- 进程1:初始化ARouter
ARouter.init(this)
- 进程2:注册Activity路由
@Route(path = "/test/activity1", name = "测试用 Activity")
public class Test1Activity extends BaseActivity {
@Autowired
int age = 10;
protected void onCreate(Bundle savedInstanceState) {
ARouter.getInstance().inject(this);
}
}
- 进程3:经过path发动对应的Activity
ARouter.getInstance().build("/test/activity2").navigation();
下面咱们分别来剖析以上进程:
进程1剖析:ARouter.init(this)
/**
* Init, it must be call before used router.
*/
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办法,进入看看
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;
}
内部初始化了一些mContext,mHandler以及字段信息
最重要的是LogisticsCenter.init
(mContext, executor):这句
进入看看:
/**
* LogisticsCenter init, load all metas in memory. Demand initialization
*/
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
try {
//运用AGP插件进行路由表的主动加载
loadRouterMap();
//假如registerByPlugin被设置为true,阐明运用的是插件加载,直接跳过
if (registerByPlugin) {
logger.info(TAG, "Load router map by arouter-auto-register plugin.");
} else {
//假如是false,则调用下面进程加载
Set<String> routerMap;
// 假如是debug形式或许是新版别的,则每次都会去加载routerMap,这会是一个耗时操作
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.
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
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>()));
}
//这儿循环获取routerMap中的信息
for (String className : routerMap) {
//假如className = "com.alibaba.android.arouter.routes.ARouter$$Root"格局,则将路由组信息添加到Warehouse.groupsIndex中
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);
//假如className = "com.alibaba.android.arouter.routes.ARouter$$Interceptors"格局,则将阻拦器信息添加到Warehouse.interceptorsIndex中
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// Load interceptorMeta
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
//假如className = "com.alibaba.android.arouter.routes.ARouter$$Providers"格局,则将服务Provider信息添加到Warehouse.providersIndex中
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// Load providerIndex
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
}
} catch (Exception e) {
throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
}
}
总结_ARouter的init操作:
- 1.优先运用插件加载路由表信息到库房中,假如没有运用插件,则运用包名com.alibaba.android.arouter.routes去dex文件中查找对应的类目标 查找到后,保存到sp文件中,非debug或许新版别的情况下,下次就直接运用sp文件中缓存的类信息即可。
- 2.查找到对应的类文件后,运用反射调用对应的类的loadInto办法,将路由组,阻拦器以及服务Provider信息加载到Warehouse库房中
持续看init办法中给的_ARouter.afterInit
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
找到/arouter/service/interceptor
注解处
@Route(path = "/arouter/service/interceptor")
public class InterceptorServiceImpl implements InterceptorService
这儿给ARouter创建了一个InterceptorServiceImpl
服务的实例目标,后边讲到阻拦器的时分会用到
进程2剖析:注册Activity路由
咱们注册的Activity,Provider等路由信息,会在编译器被注解处理器处理后生成对应的路由表:
路由表在进程1中ARouter
初始化的时分被加载到Warehouse
中
进程3剖析:经过path发动对应的Activity
ARouter.getInstance().build("/test/activity2").navigation();
这儿咱们拆分红三个部分:getInstance
,build
,navigation
- 3.1:getInstance
public static ARouter getInstance() {
if (!hasInit) {
throw new InitException("ARouter::Init::Invoke init(context) first!");
} else {
if (instance == null) {
synchronized (ARouter.class) {
if (instance == null) {
instance = new ARouter();
}
}
}
return instance;
}
}
做了init检查并创建了一个ARouter目标
- 3.2:build
public Postcard build(String path) {
return _ARouter.getInstance().build(path);
}
调用了_ARouter的同名build办法
protected Postcard build(String path) {
if (TextUtils.isEmpty(path)) {
throw new HandlerException(Consts.TAG + "Parameter is invalid!");
} else {
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
return build(path, extractGroup(path), true);
}
}
1.运用PathReplaceService,能够替换原path为新的path
持续看build办法:
protected Postcard build(String path, String group, Boolean afterReplace) {
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);
}
}
return new Postcard(path, group);
}
}
看到这儿创建了一个Postcard
,传入path和group,对Postcard前面有解说,这儿不再重复
- 3.3:navigation
最终会走到_ARouter
中的同名navigation
办法中:
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
//预处理服务
PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
// Pretreatment failed, navigation canceled.
return null;
}
try {
//完善PostCard信息 留个点1
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();
}
});
}
//没有找到路由信息,则直接回来callback.onLost
if (null != callback) {
callback.onLost(postcard);
} else {
// 没有callback则调用大局降级服务DegradeService的onLost办法
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
//回调callback.onFound提示用户现已找到path
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(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;
}
办法使命:
- 1.预处理服务
- 2.完善
PostCard
信息 - 3.假如对错绿色通道,则运用阻拦器处理恳求
- 4.调用
_navigation
处理
这儿咱们看下第3点:阻拦器处理
interceptorService.doInterceptions{
public void onContinue(Postcard postcard) {
_navigation(postcard, requestCode, callback);
}
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
}
}
假如被阻拦回调callback.onInterrupt 假如没有就履行_navigation办法
进入interceptorService.doInterceptions看下:
前面剖析过interceptorService是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计数器
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 {
//持续履行下面使命onContinue
callback.onContinue(postcard);
}
} catch (Exception e) {
callback.onInterrupt(e);
}
}
});
} else {
callback.onContinue(postcard);
}
}
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履行阻拦器
_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());
// }
}
});
}
}
}
阻拦器总结:
- 1.运用计数器对阻拦器技能,履行开端计数器+1,履行结束计数器-1,假如阻拦器履行时间到,计数器数大于0,则阐明还有未履行完结的阻拦器,这个时分就超时了退出
- 2.阻拦器履行运用递归的办法进行
- 3.阻拦器履行完结持续履行
_navigation
办法
咱们来看_navigation办法:
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = postcard.getContext();
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 (0 != flags) {
intent.setFlags(flags);
}
// Non activity, need FLAG_ACTIVITY_NEW_TASK
if (!(currentContext instanceof Activity)) {
intent.addFlags(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;
}
这个办法其实便是依据PostCard
的type
来处理不同的恳求了
- 1.Activity,直接跳转
- 2.Fragment,Provider,BroadcaseReceiver和ContentProvider,直接回来类的实例目标。
整个进程咱们就根本了解了。 上面还留了一个点:
留的点1:ARouter
是怎么完善PostCard
信息
看LogisticsCenter.completion(postcard);
进入这个办法:
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
//去Warehouse.routes去取路由元数据,开端肯定是没有的
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
//没获取到
if (null == routeMeta) {
// Maybe its does't exist, or didn't load.
//判别Warehouse.groupsIndex路由组中是否有这个group
if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {
throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
} else {
try {
//动态添加路由元信息到路由中
addRouteGroupDynamic(postcard.getGroup(), null);
} catch (Exception e) {
}
//重新加载。这个时分就会有路由元信息了
completion(postcard); // Reload
}
} else {
//给postcard设置意图地,设置类型,设置优先级,设置Extra等信息
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
Uri rawUri = postcard.getUri();
...
switch (routeMeta.getType()) {
case PROVIDER: // if the route is provider, should find its instance
// Its provider, so it must implement IProvider
Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
IProvider instance = Warehouse.providers.get(providerMeta);
if (null == instance) { // There's no instance of this provider
IProvider provider;
try {
provider = providerMeta.getConstructor().newInstance();
provider.init(mContext);
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
logger.error(TAG, "Init provider failed!", e);
throw new HandlerException("Init provider failed!");
}
}
postcard.setProvider(instance);
postcard.greenChannel(); // Provider should skip all of interceptors
break;
case FRAGMENT:
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
}
}
进入addRouteGroupDynamic
public synchronized static void addRouteGroupDynamic(String groupName, IRouteGroup group) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
if (Warehouse.groupsIndex.containsKey(groupName)){
// If this group is included, but it has not been loaded
// load this group first, because dynamic route has high priority.
Warehouse.groupsIndex.get(groupName).getConstructor().newInstance().loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(groupName);
}
// cover old group.
if (null != group) {
group.loadInto(Warehouse.routes);
}
}
看上面代码可知: 数据完善进程是经过组名group去groupsIndex获取对应的组的class目标,然后调用class目标的loadInto办法,将路由元数据加载到Warehouse.routes 然后重新调用completion完善办法去Warehouse.routes中取出路由信息并加载到PostCard中,这样PostCard中就获取到了意图地址信息。
下面我画了一张图描绘了上面的调用进程 一图胜千言
总结
本文先介绍了ARouter
运用进程中 的一些根本概念,理解了这些概念后,咱们再从运用进程触发,对每个运用节点进行了介绍。
最终运用一张图总结了整个运用原理进程:
这儿咱们还有一些悬念:
- 1.ARouter协助类是怎么生成的,这儿运用到了APT注解处理器的技能 关于APT咱们会在下一章:
Android开源系列-组件化结构Arouter-(三)APT技能详解
- 这儿还有个风趣的现象,咱们在调用路由表加载的时分:
运用了
loadRouterMap
加载,可是检查里边代码:
private static void loadRouterMap() {
registerByPlugin = false;
// auto generate register code by gradle plugin: arouter-auto-register
// looks like below:
// registerRouteRoot(new ARouter..Root..modulejava());
// registerRouteRoot(new ARouter..Root..modulekotlin());
}
居然是空的。。 呃呃呃 不要紧看注解:
auto generate register code by gradle plugin: arouter-auto-register
能够看到这儿运用了arouter-auto-register
插件中主动生成注册代码的办法:
这儿其实便是运用到了字节码插庄技能,动态添加了代码,这儿留到:
Android开源系列-组件化结构Arouter-(四)AGP插件详解
好了,本篇就到这儿了。
> 持续输出中。。你的点赞,重视是我最大的动力。