1. Android 組件化
- 組件化開發(fā)可以有效降低代碼模塊的耦合度,使代碼架構(gòu)更加清晰,同時(shí)模塊化的編譯可以有效減少編譯時(shí)間,當(dāng)然總的編譯時(shí)間是不會(huì)減少的,只是App模塊化之后開發(fā)某個(gè)模塊時(shí),只需要編譯特定模塊,可以快速編譯調(diào)試
- 將一個(gè)Module拆分成若干個(gè)Module,由主App提供統(tǒng)一的入口,每個(gè)拆分后的Module都依賴共享的Common依賴庫(kù),通過(guò)相關(guān)配置,各個(gè)Module可以獨(dú)立運(yùn)行調(diào)試,也可以供主App依賴使用。
- ARouter 原理
ARouter核心實(shí)現(xiàn)思路是,我們?cè)诖a里加入的@Route注解,會(huì)在編譯時(shí)期通 過(guò)apt生成一些存儲(chǔ)path和activityClass映射關(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)用ARouter的withString()方法它的內(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 插件化
- 隨著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).
- 插件化的優(yōu)點(diǎn)
- 宿主和插件分開編譯
- 并發(fā)開發(fā),宿主和插件都是apk,開發(fā)是互不影響的,只需要宿主給插件一個(gè)上下文
- 動(dòng)態(tài)更新插件,不需要安裝,下載之后就可以直接打開
- 按需下載模塊
- 可以解決方法數(shù)或變量數(shù)爆棚問(wèn)題
-
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文件
-
-
PathClassLoader用來(lái)加載系統(tǒng)類和應(yīng)用程序類,可以加載已經(jīng)安裝的
apk目錄下的dex文件
-
PathClassLoader用來(lái)加載系統(tǒng)類和應(yīng)用程序類,可以加載已經(jīng)安裝的
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用來(lái)加載
dex文件,可以從存儲(chǔ)空間加載dex文件。
-
DexClassLoader用來(lái)加載
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ū)別 ?
- 組件化 : 是將一個(gè)App分成多個(gè)模塊,每個(gè)模塊都是一個(gè)組件(module),開發(fā)過(guò)程中可以讓這些組件相互依賴或獨(dú)立編譯、調(diào)試部分組件,但是這些組件最終會(huì)合并成一個(gè)完整的Apk去發(fā)布到應(yīng)用市場(chǎng)。
- 插件化 : 是將整個(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