Android 组件化和插件化详解

1. Android 组件化

    1. 组件化开发可以有效降低代码模块的耦合度,使代码架构更加清晰,同时模块化的编译可以有效减少编译时间,当然总的编译时间是不会减少的,只是App模块化之后开发某个模块时,只需要编译特定模块,可以快速编译调试
    1. 将一个Module拆分成若干个Module,由主App提供统一的入口,每个拆分后的Module都依赖共享的Common依赖库,通过相关配置,各个Module可以独立运行调试,也可以供主App依赖使用。
    1. ARouter 原理

ARouter 核心实现思路是,我们在代码里加入的 @Route 注解,会在编译时期通 过 apt生成一些存储 pathactivityClass映射关系的类文件,然后 app进程启动的时候会拿到这些类文件,把保存这些映射关系的数据读到内存里(保存在 map 里),然后在进行路由跳转的时候,通过 build() 方法传入要到达页面的路由 地址,ARouter会通过它自己存储的路由表找到路由地址对应的 Activity.class(activity.class = map.get(path)),然后 new Intent(),当调用 ARouterwithString()方法它的内部会调用 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> groupsIndex = new HashMap<>();
    //用于存储已注册的所有路由
    static Map routes = new HashMap<>();  
  
    ...
}

public interface IRouteGroup {
    /**
     * Fill the atlas with routes in group.
     * atlas用于存储当前组里的所有路由,实际传入的就是Warehouse.routes
     */
    void loadInto(Map 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 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 插件化

    1. 随着apk越来越大,各种业务逻辑越来越繁杂,会达到apk开发的一个瓶颈;从业务上说,业务的繁杂会导致代码急剧的膨胀,当代码中的方法数超过65535时,就无法再容纳创建新的方法。插件化时将 apk 分为宿主和插件部分,插件在需要的时候才加载进来.
    1. 插件化的优点
  • 宿主和插件分开编译
  • 并发开发,宿主和插件都是apk,开发是互不影响的,只需要宿主给插件一个上下文
  • 动态更新插件,不需要安装,下载之后就可以直接打开
  • 按需下载模块
  • 可以解决方法数或变量数爆棚问题
    1. Android中的ClassLoader
      在Android系统中ClassLoader是用来加载dex文件的,有包含 dex 的 apk 文件以及 jar 文件,dex 文件是一种对class文件优化的产物,在Android中应用打包时会把所有class文件进行合并、优化(把不同的class文件重复的东西只保留一份),然后生成一个最终的class.dex文件
    1. PathClassLoader用来加载系统类和应用程序类,可以加载已经安装的 apk目录下的 dex文件
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);
    }
}
    1. DexClassLoader用来加载 dex文件,可以从存储空间加载 dex文件。
public class DexClassLoader extends BaseDexClassLoader {
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
}

插件化中一般使用的是 DexClassLoader

3. 组件化和插件化的区别 ?

  1. 组件化 : 是将一个App分成多个模块,每个模块都是一个组件(module),开发过程中可以让这些组件相互依赖或独立编译、调试部分组件,但是这些组件最终会合并成一个完整的Apk去发布到应用市场。
  2. 插件化 : 是将整个App拆分成很多模块,每个模块都是一个Apk(组件化的每个模块是一个lib),最终打包的时候将宿主Apk和插件Apk分开打包,只需发布宿主Apk到应用市场,插件Apk通过动态按需下发到宿主Apk

你可能感兴趣的:(Android 组件化和插件化详解)