ARouter 是阿里推出的一款頁(yè)面路由框架。由于項(xiàng)目中采用了組件化架構(gòu)進(jìn)行開(kāi)發(fā),通過(guò) ARouter 實(shí)現(xiàn)了頁(yè)面的跳轉(zhuǎn),之前看它的源碼時(shí)忘了寫(xiě)筆記,因此今天來(lái)重新對(duì)它的源碼進(jìn)行一次分析。
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供黃梅網(wǎng)站建設(shè)、黃梅做網(wǎng)站、黃梅網(wǎng)站設(shè)計(jì)、黃梅網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、黃梅企業(yè)網(wǎng)站模板建站服務(wù),十年黃梅做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
(順手留下GitHub鏈接,需要獲取相關(guān)面試或者面試寶典核心筆記PDF等內(nèi)容的可以自己去找)
https://github.com/xiangjiana/Android-MS
本篇源碼解析基于 ARouter 1.2.4
ARouter 在使用前需要通過(guò)調(diào)用 Arouter.init
方法并傳入 Application
進(jìn)行初始化:
/**
* 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.");
}
}
這里調(diào)用到了 _ARouter.init
,這個(gè) _ARouter
類才是 ARouter 的核心類:
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;
}
這里實(shí)際上調(diào)用到了 LogisticsCenter.init
:
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
mContext = context;
executor = tpe;
try {
long startInit = System.currentTimeMillis();
Set routerMap;
// 獲取存儲(chǔ) ClassName 集合的 routerMap(debug 模式下每次都會(huì)拿最新的)
if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
// 根據(jù)指定的 packageName 獲取 package 下的所有 ClassName
routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
if (!routerMap.isEmpty()) {
// 存入 SP 緩存
context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
}
} else {
logger.info(TAG, "Load router map from cache.");
// release 模式下,已經(jīng)緩存了 ClassName 列表
routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet()));
}
logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
startInit = System.currentTimeMillis();
// 遍歷 ClassName
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
// 發(fā)現(xiàn)是 Root,加載類構(gòu)建對(duì)象后通過(guò) loadInto 加載進(jìn) Warehouse.groupsIndex
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
// 發(fā)現(xiàn)是 Interceptor,加載類構(gòu)建對(duì)象后通過(guò) loadInto 加載進(jìn) Warehouse.interceptorsIndex
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
// 發(fā)現(xiàn)是 ProviderGroup,加載類構(gòu)建對(duì)象后通過(guò) loadInto 加載進(jìn) Warehouse.providersIndex
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
// ...
} catch (Exception e) {
throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
}
}
1.獲取
com.alibaba.android.arouter.routes
下存儲(chǔ)ClassName
的集合routerMap
。
2.若為 debug 模式或之前沒(méi)有解析過(guò)routerMap
,則通過(guò)ClassUtils.getFileNameByPackageName
方法對(duì)指定 package 下的所有ClassName
進(jìn)行解析并存入 SP。
3.若并非 debug 模式,并且之前已經(jīng)解析過(guò),則直接從 SP 中取出。(debug 每次都需要更新,因?yàn)轭悤?huì)隨著代碼的修改而變動(dòng))
4.遍歷routerMap
中的ClassName
。
- 如果是
RouteRoot
,則加載類構(gòu)建對(duì)象后通過(guò)loadInto
加載進(jìn)Warehouse.groupsIndex
。- 如果是
InterceptorGroup
,則加載類構(gòu)建對(duì)象后通過(guò)loadInto
加載進(jìn)Warehouse.interceptorsIndex
。- 如果是
ProviderGroup
,則加載類構(gòu)建對(duì)象后通過(guò)loadInto 加載進(jìn)
Warehouse.providersIndex`。
ClassName
我們先看看 ClassUtils.getFileNameByPackageName
是如何對(duì)指定 package 下的 ClassName
集合進(jìn)行解析的:
public static Set getFileNameByPackageName(Context context, final String packageName) {
final Set classNames = new HashSet<>();
// 通過(guò) getSourcePaths 方法獲取 dex 文件 path 集合
List paths = getSourcePaths(context);
// 通過(guò) CountDownLatch 對(duì) path 的遍歷處理進(jìn)行控制
final CountDownLatch parserCtl = new CountDownLatch(paths.size());
// 遍歷 path,通過(guò) DefaultPoolExecutor 并發(fā)對(duì) path 進(jìn)行處理
for (final String path : paths) {
DefaultPoolExecutor.getInstance().execute(new Runnable() {
@Override
public void run() {
// 加載 path 對(duì)應(yīng)的 dex 文件
DexFile dexfile = null;
try {
if (path.endsWith(EXTRACTED_SUFFIX)) {
// zip 結(jié)尾通過(guò) DexFile.loadDex 進(jìn)行加載
dexfile = DexFile.loadDex(path, path + ".tmp", 0);
} else {
// 否則通過(guò) new DexFile 加載
dexfile = new DexFile(path);
}
// 遍歷 dex 中的 Entry
Enumeration dexEntries = dexfile.entries();
while (dexEntries.hasMoreElements()) {
// 如果是對(duì)應(yīng)的 package 下的類,則添加其 className
String className = dexEntries.nextElement();
if (className.startsWith(packageName)) {
classNames.add(className);
}
}
} catch (Throwable ignore) {
Log.e("ARouter", "Scan map file in dex files made error.", ignore);
} finally {
if (null != dexfile) {
try {
dexfile.close();
} catch (Throwable ignore) {
}
}
parserCtl.countDown();
}
}
});
}
// 所有 path 處理完成后,繼續(xù)向下走
parserCtl.await();
Log.d(Consts.TAG, "Filter " + classNames.size() + " classes by packageName <" + packageName + ">");
return classNames;
}
這里的步驟比較簡(jiǎn)單,主要是如下的步驟:
1.通過(guò)
getSourcePaths
方法獲取dex
文件的 path 集合。
2.創(chuàng)建了一個(gè)CountDownLatch
控制dex
文件的并行處理,以加快速度。
3.遍歷 path 列表,通過(guò)DefaultPoolExecutor
對(duì) path 并行處理。
4.加載 path 對(duì)應(yīng)的dex
文件,并對(duì)其中的 Entry 進(jìn)行遍歷,若發(fā)現(xiàn)了對(duì)應(yīng) package 下的ClassName
,將其加入結(jié)果集合。
5.所有dex
處理完成后,返回結(jié)果
關(guān)于 getSourcePaths
如何獲取到的 dex
集合這里就不糾結(jié)了,因?yàn)槲覀兊年P(guān)注點(diǎn)不在這里。
Warehouse 實(shí)際上就是倉(cāng)庫(kù)的意思,它存放了 ARouter 自動(dòng)生成的類(RouteRoot
、InterceptorGroup
、ProviderGroup
)的信息。
我們先看看 Warehouse 類究竟是怎樣的:
class Warehouse {
// 保存 RouteGroup 對(duì)應(yīng)的 class 以及 RouteMeta
static Map> groupsIndex = new HashMap<>();
static Map routes = new HashMap<>();
// 保存 Provider 以及 RouteMeta
static Map providers = new HashMap<>();
static Map providersIndex = new HashMap<>();
// 保存 Interceptor 對(duì)應(yīng)的 class 以及 Inteceptor
static Map> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
static List interceptors = new ArrayList<>();
static void clear() {
routes.clear();
groupsIndex.clear();
providers.clear();
providersIndex.clear();
interceptors.clear();
interceptorsIndex.clear();
}
}
可以發(fā)現(xiàn) Warehouse 就是一個(gè)純粹用來(lái)存放信息的倉(cāng)庫(kù)類,它的數(shù)據(jù)的實(shí)際上是通過(guò)上面的幾個(gè)自動(dòng)生成的類在 loadInto
中對(duì) Warehouse 主動(dòng)填入數(shù)據(jù)實(shí)現(xiàn)的。
例如我們打開(kāi)一個(gè)自動(dòng)生成的 IRouteRoot
的實(shí)現(xiàn)類:
public class ARouter$$Root$$homework implements IRouteRoot {
@Override
public void loadInto(Map> routes) {
routes.put("homework", ARouter$$Group$$homework.class);
}
}
可以看到,它在 groupsIndex
中對(duì)這個(gè) RouteRoot
中的 IRouteGroup
進(jìn)行了注冊(cè),也就是向 groupIndex
中注冊(cè)了 Route Group 對(duì)應(yīng)的 IRouteGroup
類。其他類也是一樣,通過(guò)自動(dòng)生成的代碼將數(shù)據(jù)填入 Map 或 List 中。
可以發(fā)現(xiàn),初始化過(guò)程主要完成了對(duì)自動(dòng)生成的路由相關(guān)類 RouteRoot
、Interceptor
、ProviderGroup
的加載,對(duì)它們通過(guò)反射構(gòu)造后將信息加載進(jìn)了 Warehouse 類中。
下面我們看看路由的跳轉(zhuǎn)是如何實(shí)現(xiàn)的,我們先看到 ARouter.build
方法:
public Postcard build(String path) {
return _ARouter.getInstance().build(path);
}
它轉(zhuǎn)調(diào)到了 _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));
}
}
它首先通過(guò) ARouter.navigation
獲取到了 PathReplaceService
,它需要用戶進(jìn)行實(shí)現(xiàn),若沒(méi)有實(shí)現(xiàn)會(huì)返回 null,若有實(shí)現(xiàn)則調(diào)用了它的 forString
方法傳入了用戶的 Route Path 進(jìn)行路徑的預(yù)處理。
最后轉(zhuǎn)調(diào)到了 build(path, group)
,group 通過(guò) extractGroup
得到:
private String extractGroup(String path) {
if (TextUtils.isEmpty(path) || !path.startsWith("/")) {
throw new HandlerException(Consts.TAG + "Extract the default group failed, the path must be start with '/' and contain more than 2 '/'!");
}
try {
String defaultGroup = path.substring(1, path.indexOf("/", 1));
if (TextUtils.isEmpty(defaultGroup)) {
throw new HandlerException(Consts.TAG + "Extract the default group failed! There's nothing between 2 '/'!");
} else {
return defaultGroup;
}
} catch (Exception e) {
logger.warning(Consts.TAG, "Failed to extract default group! " + e.getMessage());
return null;
}
}
extractGroup
實(shí)際上就是對(duì)字符串處理,取出 Route Group 的名稱部分。
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);
}
}
build(path, group)
方法同樣也會(huì)嘗試獲取到 PathReplaceService
并對(duì) path 進(jìn)行預(yù)處理。之后通過(guò) path 與 group 構(gòu)建了一個(gè) Postcard
類:
public Postcard(String path, String group) {
this(path, group, null, null);
}
public Postcard(String path, String group, Uri uri, Bundle bundle) {
setPath(path);
setGroup(group);
setUri(uri);
this.mBundle = (null == bundle ? new Bundle() : bundle);
}
這里最終調(diào)用到了 PostCard(path, group, uri, bundle)
,這里只是進(jìn)行了一些參數(shù)的設(shè)置。
之后,如果我們調(diào)用 withInt
、withDouble
等方法,就可以進(jìn)行參數(shù)的設(shè)置。例如 withInt
方法:
public Postcard withInt(@Nullable String key, int value) {
mBundle.putInt(key, value);
return this;
}
它實(shí)際上就是在對(duì) Bundle 中設(shè)置對(duì)應(yīng)的 key、value。
最后我們通過(guò) navigation
即可實(shí)現(xiàn)最后的跳轉(zhuǎn):
public Object navigation() {
return navigation(null);
}
public Object navigation(Context context) {
return navigation(context, null);
}
public Object navigation(Context context, NavigationCallback callback) {
return ARouter.getInstance().navigation(context, this, -1, callback);
}
public void navigation(Activity mContext, int requestCode) {
navigation(mContext, requestCode, null);
}
public void navigation(Activity mContext, int requestCode, NavigationCallback callback) {
ARouter.getInstance().navigation(mContext, this, requestCode, callback);
}
通過(guò)如上的 navigation 可以看到,實(shí)際上它們都是最終調(diào)用到 ARouter.navigation
方法,在沒(méi)有傳入 Context
時(shí)會(huì)使用 Application
初始化的 Context
,并且可以通過(guò) NavigationCallback
對(duì) navigation
的過(guò)程進(jìn)行監(jiān)聽(tīng)。
public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {
return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);
}
ARouter
仍然只是將請(qǐng)求轉(zhuǎn)發(fā)到了 _ARouter
:
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
// 通過(guò) LogisticsCenter.completion 對(duì) postcard 進(jìn)行補(bǔ)全
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
// ...
}
if (null != callback) {
callback.onFound(postcard);
}
// 如果設(shè)置了 greenChannel,會(huì)跳過(guò)所有攔截器的執(zhí)行
if (!postcard.isGreenChannel()) {
// 沒(méi)有跳過(guò)攔截器,對(duì) postcard 的所有攔截器進(jìn)行執(zhí)行
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;
}
上面的代碼主要有以下步驟:
1.通過(guò)
LogisticsCenter.completion
對(duì) postcard 進(jìn)行補(bǔ)全。
2.如果postcard
沒(méi)有設(shè)置greenChannel
,則對(duì)postcard
的攔截器進(jìn)行執(zhí)行,執(zhí)行完成后調(diào)用_navigation
方法真正實(shí)現(xiàn)跳轉(zhuǎn)。
3.如果postcard
設(shè)置了greenChannel
,則直接跳過(guò)所有攔截器,調(diào)用_navigation
方法真正實(shí)現(xiàn)跳轉(zhuǎn)。
我們看看 LogisticsCenter.completion
是如何實(shí)現(xiàn) postcard
的補(bǔ)全的:
public synchronized static void completion(Postcard postcard) {
if (null == postcard) {
throw new NoRouteFoundException(TAG + "No postcard!");
}
// 通過(guò) Warehouse.routes.get 嘗試獲取 RouteMeta
RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
if (null == routeMeta) {
// 若 routeMeta 為 null,可能是并不存在,或是還沒(méi)有加載進(jìn)來(lái)
// 嘗試獲取 postcard 的 RouteGroup
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 {
// ...
// 如果找到了對(duì)應(yīng)的 RouteGroup,則將其加載進(jìn)來(lái)并重新調(diào)用 completion 進(jìn)行補(bǔ)全
IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(postcard.getGroup());
// ...
completion(postcard); // Reload
}
} else {
// 如果找到了對(duì)應(yīng)的 routeMeta,將它的信息設(shè)置進(jìn) postcard 中
postcard.setDestination(routeMeta.getDestination());
postcard.setType(routeMeta.getType());
postcard.setPriority(routeMeta.getPriority());
postcard.setExtra(routeMeta.getExtra());
Uri rawUri = postcard.getUri();
// 將 uri 中的參數(shù)設(shè)置進(jìn) bundle 中
if (null != rawUri) {
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());
}
// 對(duì)于 provider 和 fragment,進(jìn)行特殊處理
switch (routeMeta.getType()) {
case PROVIDER:
// 如果是一個(gè) provider,嘗試從 Warehouse 中查找它的類并構(gòu)造對(duì)象,然后將其設(shè)置到 provider
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);
// provider 和 fragment 都會(huì)跳過(guò)攔截器
postcard.greenChannel();
break;
case FRAGMENT:
// provider 和 fragment 都會(huì)跳過(guò)攔截器
postcard.greenChannel();
default:
break;
}
}
}
這個(gè)方法主要完成了對(duì) postcard
的信息與 Warehouse 的信息進(jìn)行結(jié)合,以補(bǔ)全 postcard
的信息,它的步驟如下:
1.通過(guò)
Warehouse.routes.get
根據(jù) path 嘗試獲取RouteMeta
對(duì)象。
2.若獲取不到RouteMeta
對(duì)象,可能是不存在或是還沒(méi)有進(jìn)行加載(第一次都未加載),嘗試獲取RouteGroup
調(diào)用其loadInto
方法將RouteMeta
加載進(jìn) Warehouse,最后調(diào)用 completion 重新嘗試補(bǔ)全 。
3.將RouteMeta
的信息設(shè)置到 postcard 中,其中會(huì)將rawUri
的參數(shù)設(shè)置進(jìn) Bundle。
4.對(duì)于Provider
和Fragment
特殊處理,其中Provider
會(huì)從Warehouse
中加載并構(gòu)造它的對(duì)象,然后設(shè)置到postcard
。Provider
和Fragment
都會(huì)跳過(guò)攔截器。
RouteGroup
的 loadInto
仍然是自動(dòng)生成的,例如下面就是一些自動(dòng)生成的代碼:
public void loadInto(Map atlas) {
atlas.put("/homework/commit", RouteMeta.build(RouteType.ACTIVITY, HomeworkCommitActivity.class, "/homework/commit", "homework", null, -1, -2147483648));
// ...
}
它包括了我們補(bǔ)全所需要的如 Destination、Class、path 等信息,在生成代碼時(shí)自動(dòng)根據(jù)注解進(jìn)行生成。
我們看看 navigation
方法是如何實(shí)現(xiàn)的跳轉(zhuǎn):
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:
// 對(duì) Activity,構(gòu)造 Intent,將參數(shù)設(shè)置進(jìn)去
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);
}
// 切換到主線程,根據(jù)是否需要 result 調(diào)用不同的 startActivity 方法
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 {
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:
// provider 直接返回對(duì)應(yīng)的 provider
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
// 對(duì)于 broadcast、contentprovider、fragment,構(gòu)造對(duì)象,設(shè)置參數(shù)后返回
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;
}
可以發(fā)現(xiàn),它會(huì)根據(jù) postcard
的 type
來(lái)分別處理:
postcard
中的參數(shù)設(shè)置進(jìn)去,之后會(huì)根據(jù)是否需要 result 調(diào)用不同的 startActivity
方法。Provider
,直接返回其對(duì)應(yīng)的 provider 對(duì)象。Broadcast
、ContentProvider
、Fragment
,反射構(gòu)造對(duì)象后,將參數(shù)設(shè)置進(jìn)去并返回。可以發(fā)現(xiàn) ARouter
的初始化和路由跳轉(zhuǎn)的整體邏輯還是不難的,實(shí)際上就是對(duì) Activity
、Fragment
的調(diào)轉(zhuǎn)過(guò)程進(jìn)行了包裝。
ARouter 除了可以通過(guò) ARouter.getInstance().build().navigation()
這樣的方式實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)之外,還可以通過(guò) ARouter.getInstance().navigation(XXService.class)
這樣的方式實(shí)現(xiàn)跨越組件的服務(wù)獲取,我們看看它是如何實(shí)現(xiàn)的:
public T navigation(Class extends T> service) {
return _ARouter.getInstance().navigation(service);
}
仍然跳轉(zhuǎn)到了_ARouter
中去實(shí)現(xiàn):
protected T navigation(Class extends T> service) {
try {
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;
}
}
這里首先通過(guò) LogisticsCenter.buildProvider
傳入service.class
的 name 構(gòu)建出了一個(gè) postcard。
而在 ARouter 老版本中,并不是通過(guò)這樣一個(gè)完整的 name 來(lái)獲取 Service 的,而是通過(guò) simpleName,下面為了兼容老版本,在獲取不到時(shí)會(huì)嘗試用老版本的方式重新構(gòu)建一次。
之后會(huì)通過(guò) LogisticsCenter.completion
對(duì) postcard 進(jìn)行補(bǔ)全,最后通過(guò) postcard.Provider
獲取對(duì)應(yīng)的 Provider。
除了 buildProvider
之外,其他方法我們已經(jīng)在前面進(jìn)行過(guò)分析,就不再贅述了:
public static Postcard buildProvider(String serviceName) {
RouteMeta meta = Warehouse.providersIndex.get(serviceName);
if (null == meta) {
return null;
} else {
return new Postcard(meta.getPath(), meta.getGroup());
}
}
這里實(shí)際上非常簡(jiǎn)單,就是通過(guò) Warehouse 中已經(jīng)初始化的 providersIndex
根據(jù) serviceName
獲取對(duì)應(yīng)的 RouteMeta
,之后根據(jù) RouteMeta
的 path 和 group 返回對(duì)應(yīng)的 Postcard
通過(guò)前面的分析,可以發(fā)現(xiàn) ARouter 中存在一套攔截器機(jī)制,在 completion 的過(guò)程中對(duì)攔截器進(jìn)行了執(zhí)行,讓我們看看它的攔截器機(jī)制的實(shí)現(xiàn)。
我們先看到 IInterceptor
接口:
public interface IInterceptor extends IProvider {
/**
* The operation of this interceptor.
*
* @param postcard meta
* @param callback cb
*/
void process(Postcard postcard, InterceptorCallback callback);
}
攔截器中主要通過(guò) process 方法完成執(zhí)行過(guò)程,可以在其中對(duì) postcard 進(jìn)行處理。而攔截器的執(zhí)行我們知道,是通過(guò)InterceptorServiceImpl.doInterceptions
實(shí)現(xiàn)的:
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.
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);
}
這里的執(zhí)行通過(guò)一個(gè) Executor 執(zhí)行,它首先構(gòu)造了一個(gè)值為 interceptors
個(gè)數(shù)的 CountDownLatch
,之后通過(guò) _execute 方法進(jìn)行執(zhí)行:
那么 ARouter
是如何自動(dòng)生成 RouteRoot
、RouteMeta
、ProviderGroup
、Provider
、Interceptor
的子類的呢?
實(shí)際上 ARouter 是通過(guò) AnnotationProcessor 配合 AutoService 實(shí)現(xiàn)的,而對(duì)于類的生成主要是通過(guò) JavaPoet 實(shí)現(xiàn)了對(duì) Java 文件的編寫(xiě),關(guān)于 JavaPoet 的具體使用可以看到其 GitHub 主頁(yè)https://github.com/xiangjiana/Android-MS
由于注解處理部分的代碼大部分就是獲取注解的屬性,并結(jié)合 JavaPoet
生成每個(gè) Element 對(duì)應(yīng)的 Java 代碼,這塊的代碼比較多且并不復(fù)雜,這里就不帶大家去看這部分的源碼了,有興趣的讀者可以看看 arouter-complier
包下的具體實(shí)現(xiàn)。
ARouter 的核心流程主要分為三部分:
編譯期注解處理
通過(guò) AnnotationProcessor
配合 JavaPoet
實(shí)現(xiàn)了編譯期根據(jù)注解對(duì) RouteRoot
、RouteMeta
、ProviderGroup
、Provider
、Interceptor
等類的代碼進(jìn)行生成,在這些類中完成了對(duì) Warehouse 中裝載注解相關(guān)信息的工作。
通過(guò)ARouter.init
,可以對(duì)ARouter
進(jìn)行初始化,它主要分為兩個(gè)步驟:
1.遍歷
Apk
的dex
文件,查找存放自動(dòng)生成類的包下的類的ClassName
集合。其中為了加快查找速度,通過(guò)一個(gè)線程池進(jìn)行了異步查找,并通過(guò)CountDownLatch
來(lái)等待所有異步查找任務(wù)的結(jié)束。這個(gè)查找過(guò)程在非 debug 模式下是有緩存的,因?yàn)?release 的 Apk 其自動(dòng)生成的類的信息必然不會(huì)變化
2.根據(jù)ClassName
的類型,分別構(gòu)建RouteRoot
、InterceptorGroup
、ProviderGroup
的對(duì)象并調(diào)用了其loadInto
方法將這些 Group 的信息裝載進(jìn) Warehouse,這個(gè)過(guò)程并不會(huì)將具體的RouteMeta
裝載。這些 Group 中主要包含了一些其對(duì)應(yīng)的下一級(jí)的信息(如RouteGroup
的 Class 對(duì)象等),之后就只需要取出下一級(jí)的信息并從中裝載,不再需要遍歷 dex 文件。
路由的過(guò)程,主要分為以下幾步:
1.通過(guò)
ARouter
中的 build(path) 方法構(gòu)建出一個(gè) Postcard,或直接通過(guò)其navigate(serviceClass)
方法構(gòu)建一個(gè) Postcard。
2.通過(guò)對(duì) Postcard 中提供的一系列方法對(duì)這次路由進(jìn)行配置,包括攜帶的參數(shù),是否跳過(guò)攔截器等等。
3.通過(guò) navigation 方法完成路由的跳轉(zhuǎn),它的步驟如下:
- a.通過(guò)
LogisticsCenter.completion
方法根據(jù) Postcard 的信息結(jié)合 Warehouse 中加載的信息對(duì) Postcard 的 Destination、Type 等信息進(jìn)行補(bǔ)全,這個(gè)過(guò)程中會(huì)實(shí)現(xiàn)對(duì)RouteMeta
信息的裝載,并且對(duì)于未跳過(guò)攔截器的類會(huì)逐個(gè)調(diào)用攔截器進(jìn)行攔截器處理。- b.根據(jù)補(bǔ)全后 Postcard 的具體類型,調(diào)用對(duì)應(yīng)的方法進(jìn)行路由的過(guò)程(如對(duì)于 Activity 調(diào)用
startActivity
,對(duì)于 Fragment 構(gòu)建對(duì)象并調(diào)用setArgument
)。4.將 navigation 的結(jié)果返回(Activity 返回的就是 null)
(順手留下GitHub鏈接,需要獲取相關(guān)面試或者面試寶典核心筆記PDF等內(nèi)容的可以自己去找)
https://github.com/xiangjiana/Android-MS