Android組件化之Application

原文首發於微信公衆號:躬行之(jzman-blog)java

上一篇文章籠統的總結了一下組件化開發的一些基礎性問題,本篇文章繼續組件化的學習,主要分以下三個方面介紹組件化中的 Application 以下:android

  1. Application的做用
  2. 合併Application
  3. 動態配置Application

Application的做用

Androuid 應用的啓動的時候最早啓動的就是 Application,每一個 App 運行時僅建立惟一一個 Application,其生命週期就是 App 的生命週期,Application 中經常使用的回調方法以下:微信

  • onCreate:建立應用程序時回調,回調時機早於任何 Activity。
  • onTerminate:終止應用程序時調用,不能保證必定會被調用。
  • onLowmemory:當後臺應用程序終止,但前臺用用程序內存還不夠時調用該方法,可在該方法中釋放一些沒必要要的資源來應對這種狀況。
  • onConfigurationChanged:配置發生變化時回調該方法,如手機屏幕旋轉等
  • onTrimMemory:通知應用的不一樣內存狀況,下面內存級別說明來自

其中附上一張來自Carson_Ho總結的 onTrimMemory 相關內存級別的說明以下:app

Application 做爲整個 App 的一個單例對象,其做用以下:ide

  1. 做爲 App 的入口,可用來初始化基本配置,如第三方 SDK 的初始化。
  2. 能夠在 Application 中定義供全局使用的變量,不過當應用被強殺以後有可能出現空指針的問題,致使再次打開應用的時候崩潰,若是肯定要這樣使用,必定要處理好這種狀況。
  3. 能夠藉助 Application 管理 Activity 的生命週期狀態以及判斷應用處於前臺仍是後臺等,可根據內存優先級下降自身應用所佔內存,減少自身應用被系統強殺的可能性。

合併Application

AndroidManifest 是每一個 Module 的聲明配置文件,對應的在生成一個 App 的時候也應該對應一份 AndroidManifest 文件,那麼在多個 Module 彼此依賴的狀況下就須要合併子 Module 的 AndroidManifest 文件內容到主 Module 的 AndroidManifest 文件中,最終會在 build 目錄下 生成最終的 AndroidManifest 文件,編譯生成的 AndroidManifest 文件的具體路徑參考以下:組件化

app\build\intermediates\manifests\full\debug\AndroidManifest.xml
複製代碼

在合併子 Modulen 的 AndroidManifest 文件時,編譯器會補全 use-sdk 的信息以及一些未設置的屬性,在合併後如 Activity 等組件中的 name 屬性都以包名+文件名來指定。post

其中在合併 AndroidManifest 文件要對 Application 進行合併, Application 合併規則以下:性能

  1. 若是子 Module 中有自定義的 Application,主 Module 中沒有自定義 Application,則會將子 Module 中的 Application 合併到最終的 AndroidManifest 文件中。
  2. 若是主 Module 有自定義 Application,子 Module 沒有自定義的 Application,則會在最終合併的 AndroidManifest 文件中使用主 Module 中的 Application。
  3. 若是多個子 Module 中都自定義了 Application,在解決衝突後則會在最終合併的 AndroidManifest 文件中使用最後編譯的 Module 中的 Application。
  4. 若是子 Module 中有自定義的 Application,子 Module 中也有自定義的 Application,此時也會提示要在主 Module 的 AndroidManifest 文件中添加 tools:replace 屬性,編譯完成以後,合併後的 AndroidManifest 文件使用的是主 Module 中自定義的 Application。

在合併過程當中若是不添加 tools:replace 屬性,則會提示添加 tools:android 屬性,提示的錯誤信息以下:學習

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:replace 屬性:ui

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 之間儘量的解耦,若是犧牲一點兒性能,可以獲取解耦的最大化也是能夠接受的。

相關文章
相關標籤/搜索