主要的类:
类名 | 类的描述 |
---|---|
ARouter | ARouter facade(门面模式); |
_ARouter | ARouter core (Facade patten) |
LogisticsCenter | LogisticsCenter contain all of the map. |
Postcard | A container that contains the roadmap. |
Warehouse | Storage of route meta and other data. |
ClassUtils | 获取ARouter自动生成的代码文件 |
在Application中初始化代码:ARouter.init(application)
;
// ARouter.class
public static void init(Application application) {
if (!hasInit) {
logger = _ARouter.logger;
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
// 初始化init()
hasInit = _ARouter.init(application);
if (hasInit) {
// 启动InterceptorService
_ARouter.afterInit();
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}
// _ARouter.class
protected static synchronized boolean init(Application application) {
mContext = application;
// LogisticsCenter的初始化
LogisticsCenter.init(mContext, executor);
logger.info(Consts.TAG, "ARouter init success!");
hasInit = true;
return true;
}
// LogisticsCenter.class
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
try {
loadRouterMap();
if (registerByPlugin) {
logger.info(TAG, "Load router map by arouter-auto-register plugin.");
} else {
Set routerMap;
// 如果是Debug模式,则执行从if代码块;
// 如果是Release模式:通过PackageUtils.isNewVersion(context)判断当前应用是否是第一次启动;
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
// 获取arouter-compiler生成的文件
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
// 存储在sp中,下次启动应用的时候,直接从sp缓存中读取
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 finish.
} else {
// 从sp缓存中读取arouter-compiler生成的文件
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet()));
}
// 遍历arouter-compiler生成的文件,将他们按照类型分别存储到Warehouse的对应字段中
for (String className : routerMap) {
// 类名前缀为com.alibaba.android.arouter.routes.ARouter$$Root的文件
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// 将类名前缀为com.alibaba.android.arouter.routes.ARouter$$Group的文件添加进Warehouse.groupsIndex中
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
}
// 类名前缀为com.alibaba.android.arouter.routes.ARouter$$Interceptors的文件
else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
}
// 类名前缀为com.alibaba.android.arouter.routes.ARouter$$Providers的文件
else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
}
//...代码省略...
} catch (Exception e) {
throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
}
}
LogisticsCenter.init()
小结:
- 查找指定包名(com.alibaba.android.arouter)下的文件,并将之缓存到SP中;
- 按照文件的前缀不同,将他们添加到路由映射表
Warehouse
的groupsIndex、interceptorsIndex、providersIndex
中;
PackageUtils
类:用来管理应用的版本
// PackageUtils .class
// 判断当前版本是否是新版本(第一次启动)
public static boolean isNewVersion(Context context) {
//...代码省略...
SharedPreferences sp = context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE);
// 从sp文件中获取之前存储的VersionName和VersionCode
if (!versionName.equals(sp.getString(LAST_VERSION_NAME, null)) || versionCode != sp.getInt(LAST_VERSION_CODE, -1)) {
//...代码省略...
return true;
} else {
return false;
}
}
// 保存当前版本的VersionName和VersionCode
public static void updateVersion(Context context) {
if (TextUtils.isEmpty(NEW_VERSION_NAME) && NEW_VERSION_CODE != 0) {
SharedPreferences sp = context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE);
sp.edit()
.putString(LAST_VERSION_NAME, NEW_VERSION_NAME)
.putInt(LAST_VERSION_CODE, NEW_VERSION_CODE)
.apply();
}
}
ClassUtils
类:获取com.alibaba.android.arouter.routes
包下 的文件:
// ClassUtils.class
// 通过指定包名,扫描包下面包含的所有的ClassName
public static Set getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException {
// Set类型的数据结构,防止重复
final Set classNames = new HashSet<>();
List paths = getSourcePaths(context);
final CountDownLatch parserCtl = new CountDownLatch(paths.size());
for (final String path : paths) {
DefaultPoolExecutor.getInstance().execute(new Runnable() {
@Override
public void run() {
DexFile dexfile = null;
try {
if (path.endsWith(EXTRACTED_SUFFIX)) {
//NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
dexfile = DexFile.loadDex(path, path + ".tmp", 0);
} else {
dexfile = new DexFile(path);
}
// 从DexFile中获取所有的文件
Enumeration dexEntries = dexfile.entries();
while (dexEntries.hasMoreElements()) {
String className = dexEntries.nextElement();
// 匹配所有包名路径为com.alibaba.android.arouter.routes的文件
if (className.startsWith(packageName)) {
classNames.add(className);
}
}
} catch (Throwable ignore) {
Log.e("ARouter", "Scan map file in dex files made error.", ignore);
} finally {
//...代码省略...
}
}
});
}
//...代码省略...
return classNames;// 返回所有包名路径为com.alibaba.android.arouter.routes的文件集合
}
Warehouse
类:路由文件映射表
class Warehouse {
// Cache route and metas
// LogisticsCenter.init() 中被赋值
static Map> groupsIndex = new HashMap<>();
// LogisticsCenter.completion(postcard) 中被赋值
static Map routes = new HashMap<>();
// Cache provider
// LogisticsCenter.completion(postcard) 中被赋值
static Map providers = new HashMap<>();
// LogisticsCenter.init() 中被赋值
static Map providersIndex = new HashMap<>();
/*
* Cache interceptor
* LogisticsCenter.init() 中被赋值;
* 此处拦截器的存储使用TreeMap,存储的时候,已经对拦截器的优先级进行排序
*/
static Map> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
// InterceptorServiceImpl.init()中被赋值
static List interceptors = new ArrayList<>();
}
至此,_ARouter.init(application)
的整个流程结束;
下面开始分析_ARouter.afterInit()
代码:
// _ARouter.class
static void afterInit() {
// Trigger interceptor init, use byName.
interceptorService = (InterceptorService)
ARouter.getInstance()
.build("/arouter/service/interceptor") //生成一个Postcard对象
//这个navigation()经过多次调用之后,
//最终调用的是_ARouter.navigation(context, postcard, requestCode, navigationCallback)方法
.navigation();
}
build("/arouter/service/interceptor")
代码分析:
// _ARouter.class
protected Postcard build(String path) {
// navigation(clazz)这种方式是属于根据类型查找,而build(path)是根据名称进行查找
// 如果应用中没有实现PathReplaceService这个接口,则pService=null
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
// PathReplaceService可以对所有的路径进行预处理,然后返回一个新的值
path = pService.forString(path);
}
//extractGroup(path)是获取分组名称,默认为path中第一部分;
return build(path, extractGroup(path));
}
// _ARouter.class
protected Postcard build(String path, String group) {
PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {
path = pService.forString(path);
}
// 返回含有path和group组别的Postcard
return new Postcard(path, group);
}
public interface PathReplaceService extends IProvider {
String forString(String path);
Uri forUri(Uri uri);
}
navigation()
代码分析:
// _ARouter.class
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
// 重点:分析部分在下面
// 1. 将IProvider映射到`Warehouse.providers`中;
// 2. 将添加@Route注解的类映射到`Warehouse.routes`中
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);
}
// 忽略拦截器(在LogisticsCenter.completion(postcard)中,PROVIDER和FRAGMENT是忽略拦截器的)
if (!postcard.isGreenChannel()) { // It must be run in async thread, maybe interceptor cost too mush time made ANR.
// interceptorService对象就是通过_ARouter.afterInit()实例化的;
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);
}
}
});
} else {
return _navigation(context, postcard, requestCode, callback);
}
return null;
}
// _ARouter.class
private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
// 这里如果navigation()不传入Activity作为context,则使用Application作为context
final Context currentContext = null == context ? mContext : context;
switch (postcard.getType()) {
case ACTIVITY:
// Build intent
final Intent intent = new Intent(currentContext, postcard.getDestination());
// Activity的参数传递
intent.putExtras(postcard.getExtras());
// Set flags.
int flags = postcard.getFlags();
if (-1 != flags) {// 如果在跳转时,设置了flags,且没有设置Activity作为context,则下面的startActivity()方法会发生错误,因为缺少Activity的Task栈;
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() {
@Override
public void run() {
if (requestCode > 0) { // Need start for result
ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
} else {
// Activity跳转
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:
//在LogisticsCenter.completion(postcard)中,我们将IProvider对象设置进postcard中,所以可以通过postcard.getProvider()获取;
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
Class fragmentMeta = postcard.getDestination();
try {
Object instance = fragmentMeta.getConstructor().newInstance();
// Fragment的参数传递
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;
}
LogisticsCenter.completion()
小结:
Warehouse.providers
中;Warehouse.routes
中;// LogisticsCenter.class
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
/*
* 根据path在Warehouse.routes映射表中查找对应的RouteMeta;
*
* 如果是第一次启动,要查找path = "/arouter/service/interceptor",
* 而此时Warehouse.routes里面是没有元素的(在LogisticsCenter.init()中,只有`Warehouse`的`groupsIndex、interceptorsIndex、providersIndex` 有数据),因此routeMeta=null
*/
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) {
// 从Warehouse.groupsIndex中取出类名前缀为com.alibaba.android.arouter.routes.ARouter$$Group$$group的文件
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 {
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
// 将我们添加@Route注解的类映射到Warehouse.routes中;
iGroupInstance.loadInto(Warehouse.routes);
// 将已经加载过的组从Warehouse.groupsIndex中移除,避免重复添加进Warehouse.routes
Warehouse.groupsIndex.remove(postcard.getGroup());
} catch (Exception e) {
throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
}
// 这个时候Warehouse.routes已经有值了,所以重新调用本方法执行else代码块
completion(postcard); // Reload
}
} else {
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());//设置routeMeta的Type
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
Uri rawUri = postcard.getUri();
if (null != rawUri) { // Try to set params into bundle.
Map resultMap = TextUtils.splitQueryParameters(rawUri);
Map paramsType = routeMeta.getParamsType();
if (MapUtils.isNotEmpty(paramsType)) {
// Set value by its type, just for params which annotation by @Param
for (Map.Entry 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 be implememt 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();
// IProvider的子类进行初始化
provider.init(mContext);
// 将IProvider的子类添加进Warehouse.providers中
Warehouse.providers.put(providerMeta, provider);
instance = provider;
} catch (Exception e) {
throw new HandlerException("Init provider failed! " + e.getMessage());
}
}
// 将IProvider的实现类保存在postcard中,因此可以从postcard获取IProvider的实例对象;
postcard.setProvider(instance);
// greenChannel()会忽略拦截器
postcard.greenChannel(); // Provider should skip all of interceptors
break;
case FRAGMENT:
// greenChannel()会忽略拦截器
postcard.greenChannel(); // Fragment needn't interceptors
default:
break;
}
}
}
到这里,我们看到了Warehouse.providers、Warehouse.routes
的赋值;那么Warehouse.interceptors
又是在哪里赋值的呢?
InterceptorServiceImpl
的初始化:
// InterceptorService是IProvider的子类
public interface InterceptorService extends IProvider {
void doInterceptions(Postcard postcard, InterceptorCallback callback);
}
/*
* 因此InterceptorServiceImpl也是IProvider的子类;
* 在LogisticsCenter.completion()中,有provider.init(context)的初始化;
*/
public class InterceptorServiceImpl implements InterceptorService {
// ...代码省略...
@Override
public void init(final Context context) {
LogisticsCenter.executor.execute(new Runnable() {
@Override
public void run() {
if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
for (Map.Entry> entry : Warehouse.interceptorsIndex.entrySet()) {
Class extends IInterceptor> interceptorClass = entry.getValue();
try {
IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
// 具体的拦截器的初始化
iInterceptor.init(context);
// 将拦截器添加到Warehouse.interceptors映射表中
Warehouse.interceptors.add(iInterceptor);
} catch (Exception ex) {
throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");
}
}
// ...代码省略...
}
}
});
}
}
至此,整个路由的初始化已经结束;
class Warehouse {
// Cache interceptor
static Map> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
}
public class UniqueKeyTreeMap<K, V> extends TreeMap<K, V> {
private String tipText;
public UniqueKeyTreeMap(String exceptionText) {
super();
tipText = exceptionText;
}
@Override
public V put(K key, V value) {
/*
* 将拦截器添加进UniqueKeyTreeMap时,以优先级priority作为键,
* 所以应用中拦截器的优先级不能重复,否则会抛出异常;
*/
if (containsKey(key)) {
throw new RuntimeException(String.format(tipText, key));
} else {
return super.put(key, value);
}
}
}
小结:
将拦截器添加进UniqueKeyTreeMap时,以优先级priority作为键,所以应用中拦截器的
优先级不能重复
,否则会抛出异常;
在使用
@Route(path= "/main/index")
进行路由标注时,会默认使用第一部分的/main
作为分组;在 build 应用后,会生成对应的ARouter$$Group$$main.java
文件;
注意:
当一个 Module 使用过
/main
组别后,其他 Module 不能再使用此作为组别,否则会出现无法找到指定文件的错误;
原因:
因为在
Warehouse
类中,有一个Map
类型的字段interceptorsIndex
,他是以组别作为Key (例如上面提到的/main
),value则是ARouter$$Group$$main.java
,所以当不同的 Module 中存在相同的组别(如/main
)时,由于Map键的唯一性,因此Warehouse.interceptorsIndex
也只能存入其中一个ARouter$$Group$$main.java
。
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
// 这里从postcard的Destination中获取需跳转的Class对象
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
// ...代码省略...
ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
//...代码省略...
}
return null;
}
// 另一种方式:通过类名直接跳转
try {
// GoodsQueryActivity.class为KitBundle组件中的页面,当前组件为MainBundle组件;通过类名查找到对应的Class,也能进行页面跳转;
Class clazz = Class.forName("com.elson.kitbundle.ui.GoodsQueryActivity");
Intent intent = new Intent(this, clazz);
startActivity(intent);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
由于拦截器的优先级具有唯一性(数据结构决定的),当在组件化开发的时候,不同组件如果都设置了拦截器的优先级,那么可能出现优先级重复的问题;
关于路由启动Activity,在启动Activity的时候添加了withFlags()
,如果 navigation()
方法没有传入 Activity作为 Context,那默认使用Application作为Context;此时会出现异常,因为用Application启动的Activity,都需要添加一个Activity栈来管理;
关于拦截器:无法拦截 IProvider
的子类和Fragment
,可在 LogisticsCenter.completion()
中找到答案;
在跳转Activity时,使用了 Postcard.withObject()
方法,则必须实现 SerializationService
接口;