ARouter 是阿里推出的一款頁(yè)面路由框架。由于項(xiàng)目中采用了組件化架構(gòu)進(jìn)行開(kāi)發(fā),通過(guò) ARouter 實(shí)現(xiàn)了頁(yè)面的跳轉(zhuǎn),之前看它的源碼時(shí)忘了寫筆記,因此今天來(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<String> 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<String>()));
}
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<String> getFileNameByPackageName(Context context, final String packageName) {
final Set<String> classNames = new HashSet<>();
// 通過(guò) getSourcePaths 方法獲取 dex 文件 path 集合
List<String> 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<String> 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<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
static Map<String, RouteMeta> routes = new HashMap<>();
// 保存 Provider 以及 RouteMeta
static Map<Class, IProvider> providers = new HashMap<>();
static Map<String, RouteMeta> providersIndex = new HashMap<>();
// 保存 Interceptor 對(duì)應(yīng)的 class 以及 Inteceptor
static 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();
}
}可以發(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<String, Class<? extends IRouteGroup>> 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<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 @Param
for (Map.Entry<String, Integer> 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<String, RouteMeta> 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> T navigation(Class<? extends T> service) {
return _ARouter.getInstance().navigation(service);
}仍然跳轉(zhuǎn)到了_ARouter 中去實(shí)現(xiàn):
protected <T> 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 文件的編寫,關(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
網(wǎng)站標(biāo)題:帶你一步一步的解析ARouter源碼
本文鏈接:http://www.jbt999.com/article34/pdpope.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開(kāi)發(fā)、網(wǎng)站設(shè)計(jì)、定制網(wǎng)站、虛擬主機(jī)、品牌網(wǎng)站建設(shè)、網(wǎng)站導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:[email protected]。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)