Android 組件化和插件化詳解

1. Android 組件化

    1. 組件化開發(fā)可以有效降低代碼模塊的耦合度,使代碼架構(gòu)更加清晰,同時(shí)模塊化的編譯可以有效減少編譯時(shí)間,當(dāng)然總的編譯時(shí)間是不會(huì)減少的,只是App模塊化之后開發(fā)某個(gè)模塊時(shí),只需要編譯特定模塊,可以快速編譯調(diào)試
    1. 將一個(gè)Module拆分成若干個(gè)Module,由主App提供統(tǒng)一的入口,每個(gè)拆分后的Module都依賴共享的Common依賴庫(kù),通過(guò)相關(guān)配置,各個(gè)Module可以獨(dú)立運(yùn)行調(diào)試,也可以供主App依賴使用。
    1. ARouter 原理

ARouter 核心實(shí)現(xiàn)思路是,我們?cè)诖a里加入的 @Route 注解,會(huì)在編譯時(shí)期通 過(guò) apt生成一些存儲(chǔ) pathactivityClass映射關(guān)系的類文件,然后 app進(jìn)程啟動(dòng)的時(shí)候會(huì)拿到這些類文件,把保存這些映射關(guān)系的數(shù)據(jù)讀到內(nèi)存里(保存在 map 里),然后在進(jìn)行路由跳轉(zhuǎn)的時(shí)候,通過(guò) build() 方法傳入要到達(dá)頁(yè)面的路由 地址,ARouter會(huì)通過(guò)它自己存儲(chǔ)的路由表找到路由地址對(duì)應(yīng)的 Activity.class(activity.class = map.get(path)),然后 new Intent(),當(dāng)調(diào)用 ARouterwithString()方法它的內(nèi)部會(huì)調(diào)用 intent.putExtra(String name, String value), 調(diào)用 navigation()方法,它的內(nèi)部會(huì)調(diào)用startActivity(intent)進(jìn)行跳轉(zhuǎn),這樣便可 以實(shí)現(xiàn)兩個(gè)相互沒有依賴的 module順利的啟動(dòng)對(duì)方的 Activity.

3.1 ARouter的原理就是所有的moudle都引用ARouter,然后再moudle中去生成一個(gè)映射表,然后再把這個(gè)映射表傳到ARouter
3.2 映射表生成 , 我們一般配置ARouter會(huì)這樣寫

@Route(path = xxx/xxx)
public class xxx{
    ......
  }

3.3 發(fā)起跳轉(zhuǎn)

ARouter.getInstance().build("/user/UserMainActivity").navigation()

ARouter的代碼要簡(jiǎn)潔很多,完全不需要手動(dòng)注冊(cè)路由就可完成跳轉(zhuǎn),它是怎么做到的呢?
3.4 很神奇!與前篇我們實(shí)現(xiàn)的路由相比,ARouter的代碼要簡(jiǎn)潔很多,完全不需要手動(dòng)注冊(cè)路由就可完成跳轉(zhuǎn),它是怎么做到的呢?
通過(guò)跟進(jìn)navigation()函數(shù)調(diào)用過(guò)程,我們把目光聚焦到兩個(gè)容器中:

  // ARouter源碼
class Warehouse {
    // Cache route and metas
    //用于存儲(chǔ)所有的路由組
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    //用于存儲(chǔ)已注冊(cè)的所有路由
    static Map<String, RouteMeta> routes = new HashMap<>();  
  
    ...
}

public interface IRouteGroup {
    /**
     * Fill the atlas with routes in group.
     * atlas用于存儲(chǔ)當(dāng)前組里的所有路由,實(shí)際傳入的就是Warehouse.routes
     */
    void loadInto(Map<String, RouteMeta> atlas);
}
 // 路由包裝類,路由目標(biāo)的Class對(duì)象就存儲(chǔ)在這里面
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對(duì)路由提出了分組概念,上面 UserMainActivity就屬于user組下,當(dāng)路由path存在2級(jí)及以上時(shí),group字段也可以省略,ARouter默認(rèn)會(huì)使用第一個(gè)反斜杠后面的path作為組名
// group可省略不寫
@Route(path = "/user/UserMainActivity")
class UserMainActivity : AppCompatActivity() {
      ...
}
  • 一般情況下,我們會(huì)將同一模塊的路由劃分在同一個(gè)組下,例如App模塊下的所有路由都在“app”這個(gè)分組下 , user模塊的路由都在“user”分組下;當(dāng)然,同一模塊擁有多個(gè)分組也是完全可行的,只要保證與其它模塊中的路由分組不重名即可

分析這兩個(gè)容器的作用,大致如下:
1、當(dāng)傳入path進(jìn)行跳轉(zhuǎn)時(shí),優(yōu)先從Warehouse.routes中直接獲取路由對(duì)象;
2、路由對(duì)象不存在,就需要通過(guò)Warehouse.groupsIndex路由組來(lái)完成注冊(cè)功能
3、注冊(cè)成功后,當(dāng)前path所在組的所有路由都將存儲(chǔ)到Warehouse.routes中;
4、回到第1步,獲取路由對(duì)象;
5、讀取路由對(duì)象信息;
6、完成跳轉(zhuǎn)

2. Android 插件化

    1. 隨著apk越來(lái)越大,各種業(yè)務(wù)邏輯越來(lái)越繁雜,會(huì)達(dá)到apk開發(fā)的一個(gè)瓶頸;從業(yè)務(wù)上說(shuō),業(yè)務(wù)的繁雜會(huì)導(dǎo)致代碼急劇的膨脹,當(dāng)代碼中的方法數(shù)超過(guò)65535時(shí),就無(wú)法再容納創(chuàng)建新的方法。插件化時(shí)將 apk 分為宿主和插件部分,插件在需要的時(shí)候才加載進(jìn)來(lái).
    1. 插件化的優(yōu)點(diǎn)
  • 宿主和插件分開編譯
  • 并發(fā)開發(fā),宿主和插件都是apk,開發(fā)是互不影響的,只需要宿主給插件一個(gè)上下文
  • 動(dòng)態(tài)更新插件,不需要安裝,下載之后就可以直接打開
  • 按需下載模塊
  • 可以解決方法數(shù)或變量數(shù)爆棚問(wèn)題
    1. Android中的ClassLoader
      在Android系統(tǒng)中ClassLoader是用來(lái)加載dex文件的,有包含 dex 的 apk 文件以及 jar 文件,dex 文件是一種對(duì)class文件優(yōu)化的產(chǎn)物,在Android中應(yīng)用打包時(shí)會(huì)把所有class文件進(jìn)行合并、優(yōu)化(把不同的class文件重復(fù)的東西只保留一份),然后生成一個(gè)最終的class.dex文件
    1. PathClassLoader用來(lái)加載系統(tǒng)類和應(yīng)用程序類,可以加載已經(jīng)安裝的 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用來(lái)加載 dex文件,可以從存儲(chǔ)空間加載 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. 組件化和插件化的區(qū)別 ?

  1. 組件化 : 是將一個(gè)App分成多個(gè)模塊,每個(gè)模塊都是一個(gè)組件(module),開發(fā)過(guò)程中可以讓這些組件相互依賴或獨(dú)立編譯、調(diào)試部分組件,但是這些組件最終會(huì)合并成一個(gè)完整的Apk去發(fā)布到應(yīng)用市場(chǎng)。
  2. 插件化 : 是將整個(gè)App拆分成很多模塊,每個(gè)模塊都是一個(gè)Apk(組件化的每個(gè)模塊是一個(gè)lib),最終打包的時(shí)候?qū)⑺拗鰽pk和插件Apk分開打包,只需發(fā)布宿主Apk到應(yīng)用市場(chǎng),插件Apk通過(guò)動(dòng)態(tài)按需下發(fā)到宿主Apk
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容