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