PS:不想看專業的知識就看點感興趣的知識,總之不要過於慵懶。
上一篇文章籠統的總結了一下組件化開發的一些基礎性問題,本篇文章繼續組件化的學習,主要分如下三個方面介紹組件化中的 Application 如下:
- Application 的作用
- 合併 Application
- 動態配置 Application
Application 的作用#
Androuid 應用的啟動的時候最先啟動的就是 Application,每個 App 運行時僅創建唯一一個 Application,其生命週期就是 App 的生命週期,Application 中常用的回調方法如下:
- onCreate:創建應用程序時回調,回調時機早於任何 Activity。
- onTerminate:終止應用程序時調用,不能保證一定會被調用。
- onLowmemory:當後台應用程序終止,但前台用用程序內存還不夠時調用該方法,可在該方法中釋放一些不必要的資源來應對這種情況。
- onConfigurationChanged:配置發生變化時回調該方法,如手機螢幕旋轉等
- onTrimMemory:通知應用的不同內存情況,下面內存級別說明來自
其中附上一張來自Carson_Ho總結的 onTrimMemory 相關內存級別的說明如下:
Application 作為整個 App 的一個單例對象,其作用如下:
- 作為 App 的入口,可用來初始化基本配置,如第三方 SDK 的初始化。
- 可以在 Application 中定義供全局使用的變量,不過當應用被強殺之後有可能出現空指針的問題,導致再次打開應用的時候崩潰,如果確定要這樣使用,一定要處理好這種情況。
- 可以借助 Application 管理 Activity 的生命週期狀態以及判斷應用處於前台還是後台等,可根據內存優先級降低自身應用所占內存,減小自身應用被系統強殺的可能性。
合併 Application#
AndroidManifest 是每個 Module 的聲明配置文件,對應的在生成一個 App 的時候也應該對應一份 AndroidManifest 文件,那麼在多個 Module 彼此依賴的情況下就需要合併子 Module 的 AndroidManifest 文件內容到主 Module 的 AndroidManifest 文件中,最終會在 build 目錄下 生成最終的 AndroidManifest 文件,編譯生成的 AndroidManifest 文件的具體路徑參考如下:
app\build\intermediates\manifests\full\debug\AndroidManifest.xml
在合併子 Module 的 AndroidManifest 文件時,編譯器會補全 use-sdk 的信息以及一些未設置的屬性,在合併後如 Activity 等組件中的 name 屬性都以包名 + 文件名來指定。
其中在合併 AndroidManifest 文件要對 Application 進行合併, Application 合併規則如下:
- 如果子 Module 中有自定義的 Application,主 Module 中沒有自定義 Application,則會將子 Module 中的 Application 合併到最終的 AndroidManifest 文件中。
- 如果主 Module 有自定義 Application,子 Module 沒有自定義的 Application,則會在最終合併的 AndroidManifest 文件中使用主 Module 中的 Application。
- 如果多個子 Module 中都自定義了 Application,在解決衝突後則會在最終合併的 AndroidManifest 文件中使用最後編譯的 Module 中的 Application。
- 如果子 Module 中有自定義的 Application,子 Module 中也有自定義的 Application,此時也會提示要在主 Module 的 AndroidManifest 文件中添加 tools 屬性,編譯完成之後,合併後的 AndroidManifest 文件使用的是主 Module 中自定義的 Application。
在合併過程中如果不添加 tools 屬性,則會提示添加 tools 屬性,提示的錯誤信息如下:
Manifest merger failed : Attribute application@name value=(com.manu.module_one.OneApplication) from [:moduel_one] AndroidManifest.xml:13:9-58
is also present at [:module_two] AndroidManifest.xml:13:9-58 value=(com.manu.module_two.TwoApplication).
Suggestion: add 'tools:replace="android:name"' to <application> element at AndroidManifest.xml:6:5-21:19 to override.
比如這裡就要在子 Module 中的 AndroidManifest 文件的 application 標籤下添加 tools 屬性:
tools:replace="android:name"
動態配置 Application#
除了 Application 需要合併之外,在組件化過程中各個 Module 的初始化也非常重要,可以使用反射完成各個 Module 的初始化,就是在主 Module 中反射獲取子 Module 的初始化對象,然後調用其初始化方法,為了方便定義一個類管理子 Module 的初始化類,參考如下:
/**
* Created by jzman
* Powered by 2019/04/15 0022.
*/
public class ModuleConfig {
private static final String moduleOneInit = "com.manu.module_one.ModuleOneAppInit";
private static final String moduleTwoInit = "com.manu.module_two.ModuleTwoAppInit";
public static String[] moduleInits = {
moduleOneInit,
moduleTwoInit
};
}
創建一個初始化的基類接口如下:
/**
* 統一App初始化接口
* Created by jzman
* Powered by 2019/04/15 0022.
*/
public interface BaseAppInit {
/**
* 高優先級被初始化
* @param application
* @return
*/
boolean onInitHighPriority(Application application);
/**
* 低優先級被初始化
* @param application
* @return
*/
boolean onInitLowPriority(Application application);
}
為了使得每個子 Module 都能方便使用該初始化基類,應將其放在基類 Module 中,因為基類被所有的 Module 所依賴,然後在每個子 Module 中繼承 BaseAppInit 實現自己 Module 的初始化類,參考如下:
/**
* module_one初始化文件
* Created by jzman
* Powered by 2019/04/15 0022.
*/
public class ModuleOneAppInit implements BaseAppInit {
private static final String TAG = ModuleOneAppInit.class.getSimpleName();
@Override
public boolean onInitHighPriority(Application application) {
Log.i(TAG, "ModuleOneAppInit---onInitHighPriority");
return true;
}
@Override
public boolean onInitLowPriority(Application application) {
Log.i(TAG, "ModuleOneAppInit---onInitLowPriority");
return true;
}
}
最後在主 Module 的自定義的 Application 中通過反射創建各個子 Module 的初始化類對象,並調用其初始化方法,參考如下:
/**
* 高優先級初始化
*/
private void initModuleHighPriority(){
for (String init: ModuleConfig.moduleInits){
try {
Class<?> clazz = Class.forName(init);
BaseAppInit appInit = (BaseAppInit) clazz.newInstance();
appInit.onInitHighPriority(this);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
/**
* 低優先級初始化
*/
private void initModuleLowPriority(){
for (String init: ModuleConfig.moduleInits){
try {
Class<?> clazz = Class.forName(init);
BaseAppInit appInit = (BaseAppInit) clazz.newInstance();
appInit.onInitLowPriority(this);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
運行日誌如下:
ModuleOneAppInit---onInitHighPriority
ModuleTwoAppInit---onInitHighPriority
ModuleOneAppInit---onInitLowPriority
ModuleTwoAppInit---onInitLowPriority
此外,還可以在基類 Module 中創建初始化基類和 BaseApplication,然後在 BaseApplication 中反射調用具體的初始化方法,歸根結底還是使用反射,只是另一種實現方式,首先在基類 moddule 中創建 BaseAppInit 如下:
/**
* Created by jzman
* Powered by 2019/04/15 0022.
*/
public abstract class BaseAppInit {
private Application mApplication;
public BaseAppInit() {
}
public void setApplication(@NonNull Application application) {
this.mApplication = application;
}
public void onCreate(){}
public void OnTerminate(){}
public void onLowMemory(){}
public void configurationChanged(Configuration configuration){}
}
在基類 Module 中創建 BaseApplication 如下:
/**
* Created by jzman
* Powered by 2019/04/15 0023.
*/
public abstract class BaseApplication extends Application {
private List<Class<? extends BaseAppInit>> classInitList = new ArrayList<>();
private List<BaseAppInit> appInitList = new ArrayList<>();
@Override
public void onCreate() {
super.onCreate();
appInit();
initCreate();
}
protected abstract void appInit();
protected void registerApplicationInit(Class<? extends BaseAppInit> classInit) {
classInitList.add(classInit);
}
private void initCreate() {
for (Class<? extends BaseAppInit> classInit : classInitList) {
try {
BaseAppInit appInit = classInit.newInstance();
appInitList.add(appInit);
appInit.onCreate();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
@Override
public void onTerminate() {
super.onTerminate();
for (BaseAppInit appInit : appInitList) {
appInit.OnTerminate();
}
}
@Override
public void onLowMemory() {
super.onLowMemory();
for (BaseAppInit appInit : appInitList) {
appInit.onLowMemory();
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
for (BaseAppInit appInit : appInitList) {
appInit.configurationChanged(newConfig);
}
}
}
然後在子 Module 中實現具體的初始化類,參考如下:
/**
* Created by jzman
* Powered by 2019/04/15 0023.
*/
public class ModuleThreeAppInit extends BaseAppInit {
private static final String TAG = ModuleThreeAppInit.class.getSimpleName();
@Override
public void onCreate() {
Log.i(TAG, "ModuleThreeAppInit---onCreate");
}
}
最後,在主 Module 中繼承 BaseApplication 實現自定義的 Application,並註冊每個子 Module 的初始化文件,參考如下:
/**
* Created by jzman
* Powered by 2019/04/15 0023.
*/
public class MApplication extends BaseApplication{
@Override
protected void appInit() {
registerApplicationInit(ModuleThreeAppInit.class);
registerApplicationInit(ModuleForeAppInit.class);
}
}
運行日誌如下:
ModuleThreeAppInit---onCreate
ModuleForeAppInit---onCreate
如上兩種方式都是使用了反射,發射在解耦的同時,也在一定程度上降低了應用的性能,當然組件化的目的就是要讓各個組件或各個 Module 之間儘可能的解耦,如果犧牲一點兒性能,能夠獲取解耦的最大化也是可以接受的。