阿里路由框架--ARouter 源码解析之初始化ARouter
来源:互联网 发布:d3.js 动态折线图 编辑:程序博客网 时间:2024/06/05 17:49
转载请注明出处:http://blog.csdn.net/crazy1235/article/details/77337691
- 初始化ARouter
- openLog
- openDebug
- init
- LogisticsCenterinit
- getFileNameByPackageName
- getSourcePaths
- tryLoadInstantRunDexFile
- afterInit
- 参考
- 初始化ARouter
上一篇介绍了ARouter的Compiler SDK : 阿里路由框架–ARouter 源码解析之Compiler
在编译阶段会根据注解生成相应的 java 类文件。
接下来分析一下 arouter-api SDK
先来看看目录结构:
初始化ARouter
ARouter.openLog();ARouter.openDebug();ARouter.init(getApplication());
openLog()
ARouter.java
public static synchronized void openLog() { _ARouter.openLog(); }
_ARouter.java
static ILogger logger = new DefaultLogger(Consts.TAG);
ILogger是一个接口,定义了一些日志输出函数
public class DefaultLogger implements ILogger
static synchronized void openLog() { logger.showLog(true); logger.info(Consts.TAG, "ARouter openLog"); }
ARouter中的函数基本都是通过调用_ARouter类中的函数来实现的,这里应用了一种 外观模式
openDebug()
public static synchronized void openDebug() { _ARouter.openDebug(); }
// //设置debug模式static synchronized void openDebug() { debuggable = true; logger.info(Consts.TAG, "ARouter openDebug"); }
init()
初始化ARouter
private volatile static boolean hasInit = false;
public static void init(Application application) { if (!hasInit) { logger = _ARouter.logger; // log _ARouter.logger.info(Consts.TAG, "ARouter init start."); // 调用_ARouter的init函数 hasInit = _ARouter.init(application); // 调用afterInit() if (hasInit) { _ARouter.afterInit(); } _ARouter.logger.info(Consts.TAG, "ARouter init over."); } }
_ARouter.java
protected static synchronized boolean init(Application application) { mContext = application; // 初始化 “处理中心” LogisticsCenter.init(mContext, executor); logger.info(Consts.TAG, "ARouter init success!"); hasInit = true; return true; }
LogisticsCenter.init()
// 线程池执行对象private volatile static ThreadPoolExecutor executor = DefaultPoolExecutor.getInstance();
// compile编译阶段生成的类文件都在此目录下public static final String ROUTE_ROOT_PAKCAGE = "com.alibaba.android.arouter.routes";
/** * */ public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException { mContext = context; executor = tpe; try { // 根据报名加载下面所有的类文件(也就是ARouter编译生成的文件) List<String> classFileNames = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE); // 遍历文件 for (String className : classFileNames) { // 如果是 文件名是 com.alibaba.android.arouter.routes.ARouter$$Root 开头的文件,表示是一个Root类型的文件。 if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) { // 创建Root类对象,并放入到WareHouse这个仓库中 ((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); } } if (Warehouse.groupsIndex.size() == 0) { logger.error(TAG, "No mapping files were found, check your configuration please!"); } if (ARouter.debuggable()) { logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size())); } } catch (Exception e) { throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]"); } }
Warehouse 类是一个仓库,用来存储路由信息以及 provider , interceptor 等信息。
接下来重点看怎么获取ARouter compile生成的类文件
getFileNameByPackageName()
ARouter有如下特性:
支持InstantRun
支持MultiDex(Google方案)
所以下面这个函数就显得很重要!!!
/** * 通过指定包名,扫描包下面包含的所有的ClassName * * @param context U know * @param packageName 包名 * @return 所有class的集合 */ public static List<String> getFileNameByPackageName(Context context, String packageName) throws PackageManager.NameNotFoundException, IOException { List<String> classNames = new ArrayList<>(); // 先去得到所有的dex文件,然后进行遍历 for (String path : getSourcePaths(context)) { 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); } Enumeration<String> dexEntries = dexfile.entries(); while (dexEntries.hasMoreElements()) { String className = dexEntries.nextElement(); if (className.contains(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) { } } } } Log.d("ARouter", "Filter " + classNames.size() + " classes by packageName <" + packageName + ">"); return classNames; }
getSourcePaths()
/** * get all the dex path * * @param context the application context * @return all the dex path * @throws PackageManager.NameNotFoundException * @throws IOException */ public static List<String> getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException { ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0); // /data/app/com.alibaba.android.arouter.demo-2/base.apk File sourceApk = new File(applicationInfo.sourceDir); List<String> sourcePaths = new ArrayList<>(); sourcePaths.add(applicationInfo.sourceDir); //add the default apk path //the prefix of extracted file, ie: test.classes String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT;// 如果VM已经支持了MultiDex,就不要去Secondary Folder加载 Classesx.zip了,那里已经么有了// 通过是否存在sp中的multidex.version是不准确的,因为从低版本升级上来的用户,是包含这个sp配置的 if (!isVMMultidexCapable()) { //the total dex numbers int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1); File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME); for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) { //for each dex file, ie: test.classes2.zip, test.classes3.zip... String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX; File extractedFile = new File(dexDir, fileName); if (extractedFile.isFile()) { sourcePaths.add(extractedFile.getAbsolutePath()); //we ignore the verify zip part } else { throw new IOException("Missing extracted secondary dex file '" + extractedFile.getPath() + "'"); } } } if (ARouter.debuggable()) { // Search instant run support only debuggable sourcePaths.addAll(tryLoadInstantRunDexFile(applicationInfo)); } return sourcePaths; }
tryLoadInstantRunDexFile()
加载InstantRun 模式下的dex文件
/** * Get instant run dex path, used to catch the branch usingApkSplits=false. */ private static List<String> tryLoadInstantRunDexFile(ApplicationInfo applicationInfo) { List<String> instantRunSourcePaths = new ArrayList<>(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && null != applicationInfo.splitSourceDirs) { // add the splite apk, normally for InstantRun, and newest version. instantRunSourcePaths.addAll(Arrays.asList(applicationInfo.splitSourceDirs)); Log.d("ARouter", "Found InstantRun support"); } else { try { // This man is reflection from Google instant run sdk, he will tell me where the dex files go. Class pathsByInstantRun = Class.forName("com.android.tools.fd.runtime.Paths"); Method getDexFileDirectory = pathsByInstantRun.getMethod("getDexFileDirectory", String.class); String instantRunDexPath = (String) getDexFileDirectory.invoke(null, applicationInfo.packageName); File instantRunFilePath = new File(instantRunDexPath); if (instantRunFilePath.exists() && instantRunFilePath.isDirectory()) { File[] dexFile = instantRunFilePath.listFiles(); for (File file : dexFile) { if (null != file && file.exists() && file.isFile() && file.getName().endsWith(".dex")) { instantRunSourcePaths.add(file.getAbsolutePath()); } } Log.d("ARouter", "Found InstantRun support"); } } catch (Exception e) { Log.e("ARouter", "InstantRun support error, " + e.getMessage()); } } return instantRunSourcePaths; }
afterInit()
static void afterInit() { // Trigger interceptor init, use byName. interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation(); }
参考
http://blog.csdn.net/fei20121106/article/details/73743235
阅读全文
1 0
- 阿里路由框架--ARouter 源码解析之初始化ARouter
- 阿里路由框架--ARouter 源码解析之Compiler
- ARouter源码解析02-加载路由表单
- ARouter源码解析03-路由跳转
- ARouter路由框架介绍
- ARouter 路由框架
- 阿里ARouter源码分析
- (4.2.40)阿里开源路由框架ARouter的源码分析
- 【PDF下载】阿里开源峰会之安卓页面路由框架ARouter最佳实践
- ARouter Android页面路由框架
- 浅谈Android模块化设计(路由框架ARouter源码分析)
- ARouter源码解析06-openDebug
- [源码]ARouter
- Android平台阿里页面路由ARouter
- ARouter
- Android 路由框架ARouter最佳实践
- Android 路由框架ARouter最佳实践
- ARouter源码分析初始化以及跳转
- [luogu1004]方格取数(dp,亚瑟)
- 第3章_堆栈和队列
- a
- 浮点数与十六进制的转换
- binary-tree-maximum-path-sum
- 阿里路由框架--ARouter 源码解析之初始化ARouter
- c/c++基础题(1)
- 页面乱码问题总结
- robotframework+jenkins运行报Build step 'Execute Windows batch command' marked build as failure解决方法
- Android-PickerView系列之介绍与使用篇(一)
- ActiveSQLite更简单的Swift数据库方案(SQLite.swift封装)
- HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
- 贷款展期
- 某安全浏览器竟然也被查出高危漏洞?开源安全问题不容忽视