1. Android 组件化
- 组件化开发可以有效降低代码模块的耦合度,使代码架构更加清晰,同时模块化的编译可以有效减少编译时间,当然总的编译时间是不会减少的,只是App模块化之后开发某个模块时,只需要编译特定模块,可以快速编译调试
- 将一个Module拆分成若干个Module,由主App提供统一的入口,每个拆分后的Module都依赖共享的Common依赖库,通过相关配置,各个Module可以独立运行调试,也可以供主App依赖使用。
- ARouter 原理
ARouter
核心实现思路是,我们在代码里加入的@Route
注解,会在编译时期通 过apt
生成一些存储path
和activityClass
映射关系的类文件,然后app
进程启动的时候会拿到这些类文件,把保存这些映射关系的数据读到内存里(保存在 map 里)
,然后在进行路由跳转的时候,通过build()
方法传入要到达页面的路由 地址,ARouter
会通过它自己存储的路由表找到路由地址对应的Activity.class(activity.class = map.get(path))
,然后new Intent()
,当调用ARouter
的withString()
方法它的内部会调用intent.putExtra(String name, String value)
, 调用navigation()
方法,它的内部会调用startActivity(intent)
进行跳转,这样便可 以实现两个相互没有依赖的module
顺利的启动对方的Activity
.
3.1 ARouter
的原理就是所有的moudle
都引用ARouter
,然后再moudle
中去生成一个映射表,然后再把这个映射表传到ARouter
中
3.2 映射表生成 , 我们一般配置ARouter会这样写
@Route(path = xxx/xxx)
public class xxx{
......
}
3.3 发起跳转
ARouter.getInstance().build("/user/UserMainActivity").navigation()
ARouter的代码要简洁很多,完全不需要手动注册路由就可完成跳转,它是怎么做到的呢?
3.4 很神奇!与前篇我们实现的路由相比,ARouter的代码要简洁很多,完全不需要手动注册路由就可完成跳转,它是怎么做到的呢?
通过跟进navigation()函数调用过程,我们把目光聚焦到两个容器中:
// ARouter源码
class Warehouse {
// Cache route and metas
//用于存储所有的路由组
static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
//用于存储已注册的所有路由
static Map<String, RouteMeta> routes = new HashMap<>();
...
}
public interface IRouteGroup {
/**
* Fill the atlas with routes in group.
* atlas用于存储当前组里的所有路由,实际传入的就是Warehouse.routes
*/
void loadInto(Map<String, RouteMeta> atlas);
}
// 路由包装类,路由目标的Class对象就存储在这里面
public class RouteMeta {
private RouteType type; // Type of route
private Element rawType; // Raw type of route
private Class<?> destination; // Destination
private String path; // Path of route
private String group; // Group of route
private int priority = -1; // The smaller the number, the higher the priority
private int extra; // Extra data
private Map<String, Integer> paramsType; // Param type
private String name;
...
}
- ARouter对路由提出了分组概念,上面 UserMainActivity就属于user组下,当路由path存在2级及以上时,group字段也可以省略,ARouter默认会使用第一个反斜杠后面的path作为组名
// group可省略不写
@Route(path = "/user/UserMainActivity")
class UserMainActivity : AppCompatActivity() {
...
}
- 一般情况下,我们会将同一模块的路由划分在同一个组下,例如App模块下的所有路由都在“app”这个分组下 , user模块的路由都在“user”分组下;当然,同一模块拥有多个分组也是完全可行的,只要保证与其它模块中的路由分组不重名即可
分析这两个容器的作用,大致如下:
1、当传入path进行跳转时,优先从Warehouse.routes中直接获取路由对象;
2、路由对象不存在,就需要通过Warehouse.groupsIndex路由组来完成注册功能
3、注册成功后,当前path所在组的所有路由都将存储到Warehouse.routes中;
4、回到第1步,获取路由对象;
5、读取路由对象信息;
6、完成跳转
2. Android 插件化
- 随着apk越来越大,各种业务逻辑越来越繁杂,会达到apk开发的一个瓶颈;从业务上说,业务的繁杂会导致代码急剧的膨胀,当代码中的方法数超过65535时,就无法再容纳创建新的方法。插件化时将 apk 分为宿主和插件部分,插件在需要的时候才加载进来.
- 插件化的优点
- 宿主和插件分开编译
- 并发开发,宿主和插件都是apk,开发是互不影响的,只需要宿主给插件一个上下文
- 动态更新插件,不需要安装,下载之后就可以直接打开
- 按需下载模块
- 可以解决方法数或变量数爆棚问题
-
Android
中的ClassLoader
在Android系统中ClassLoader
是用来加载dex文件的,有包含 dex 的 apk 文件以及 jar 文件,dex 文件是一种对class文件优化的产物,在Android中应用打包时会把所有class文件进行合并、优化(把不同的class文件重复的东西只保留一份),然后生成一个最终的class.dex文件
-
-
PathClassLoader用来加载系统类和应用程序类,可以加载已经安装的
apk
目录下的dex
文件
-
PathClassLoader用来加载系统类和应用程序类,可以加载已经安装的
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String libraryPath,
ClassLoader parent) {
super(dexPath, null, libraryPath, parent);
}
}
-
DexClassLoader用来加载
dex
文件,可以从存储空间加载dex
文件。
-
DexClassLoader用来加载
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
}
插件化中一般使用的是
DexClassLoader
3. 组件化和插件化的区别 ?
- 组件化 : 是将一个App分成多个模块,每个模块都是一个组件(module),开发过程中可以让这些组件相互依赖或独立编译、调试部分组件,但是这些组件最终会合并成一个完整的Apk去发布到应用市场。
- 插件化 : 是将整个App拆分成很多模块,每个模块都是一个Apk(组件化的每个模块是一个lib),最终打包的时候将宿主Apk和插件Apk分开打包,只需发布宿主Apk到应用市场,插件Apk通过动态按需下发到宿主Apk