導(dǎo)讀
- 移動開發(fā)知識體系總章(Java基礎(chǔ)、Android、Flutter)
- Application是什么
- Application生命周期
- 使用Application傳遞數(shù)據(jù)
- 使用Application數(shù)據(jù)緩存
- Application的context
- Application的oncreate方法會執(zhí)行幾次,會不會多次執(zhí)行?
- 使用Application避免一些內(nèi)存泄漏
Application是什么
Application和Activity、Service一樣是Android框架的一個系統(tǒng)組件,當(dāng)Android程序啟動時系統(tǒng)會創(chuàng)建一個 Application對象,用來存儲系統(tǒng)的一些信息。
Application的生命周期等于這個程序的生命周期,又因?yàn)锳pplication是全局的單例的,所以在不同的Activity,Service中獲得的對象都是同一個對象。所以通過Application來進(jìn)行一些數(shù)據(jù)傳遞、數(shù)據(jù)共享、數(shù)據(jù)緩存等操作。
一般寫Demo是不需要指定一個Application的,這時系統(tǒng)會自動幫我們創(chuàng)建;而實(shí)際項(xiàng)目中基本上都是需要創(chuàng)建自己的Application的,創(chuàng)建一個類繼承 Application并在AndroidManifest清單文件中的Application標(biāo)簽中進(jìn)行注冊(只需要給Application標(biāo)簽增加個name屬性把自己的 Application的名字定入即可)。android系統(tǒng)會為每個程序運(yùn)行時創(chuàng)建一個Application類的對象且僅創(chuàng)建一個,所以Application可以說是單例 (singleton)模式的一個類。
Application生命周期
- onConfigurationChanged( ) :在配置被改變時觸發(fā) 。
- onCreate() :在程序創(chuàng)建時創(chuàng)建。
- onLowMemory() :內(nèi)存不夠時觸發(fā)。
- onTerminate() :當(dāng)終止程序時調(diào)用 但是不能保證一定調(diào)用
- onTrimMemory() :在內(nèi)存清理時觸發(fā)
public class App extends Application {
@Override
public void onCreate() {
// 程序創(chuàng)建的時候執(zhí)行
Log.d(TAG, "onCreate");
super.onCreate();
}
@Override
public void onTerminate() {
// 程序終止的時候執(zhí)行
Log.d(TAG, "onTerminate");
super.onTerminate();
}
@Override
public void onLowMemory() {
// 低內(nèi)存的時候執(zhí)行
Log.d(TAG, "onLowMemory");
super.onLowMemory();
}
@Override
public void onTrimMemory(int level) {
// 程序在內(nèi)存清理的時候執(zhí)行
Log.d(TAG, "onTrimMemory");
super.onTrimMemory(level);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
Log.d(TAG, "onConfigurationChanged");
super.onConfigurationChanged(newConfig);
}
}
使用Application傳遞數(shù)據(jù)
在android中通常會使用Intent(Bundle)進(jìn)行數(shù)據(jù)通信,但一般為簡單數(shù)據(jù)類型,如數(shù)據(jù)類型相對復(fù)雜(如對象)則需要實(shí)現(xiàn) Serializable或者Parcelable接口,其實(shí)可以使用Application傳遞復(fù)雜數(shù)據(jù)。
基本思路是這樣的。在Application中創(chuàng)建一個HashMap ,以字符串為key,Object為value這樣我們的HashMap就可以存儲任何類型的對象了
使用Application數(shù)據(jù)緩存
既然可以在Application中使用HashMap 進(jìn)行傳遞數(shù)據(jù),自然是可以進(jìn)行一些緩存動作了,不過筆者基本沒有這樣操作過,同時需要注意內(nèi)存泄漏。
Application的Context
- Context是一個應(yīng)用程序環(huán)境的信息,即上下文。
- 該類是一個抽象(abstract class)類,Android提供了該抽象類的具體實(shí)現(xiàn)類(后面我們會講到是ContextIml類)。
-
通過它我們可以獲取應(yīng)用程序的資源和類,也包括一些應(yīng)用級別操作,例如:啟動一個Activity,發(fā)送廣播,接受Intent信息 等
Context
可以看到Activity、Service、Application都是Context的子類。
也就是說,Android系統(tǒng)的角度來理解:Context是一個場景,代表與操作系統(tǒng)的交互的一種過程。從程序的角度上來理解:Context是個抽象類,而Activity、Service、Application等都是該類的一個實(shí)現(xiàn)。
Application的oncreate方法會執(zhí)行幾次,會不會多次執(zhí)行?
通常情況下,App默認(rèn)開啟一個進(jìn)程,進(jìn)程名就是AndroidManifest.xml文件中我們項(xiàng)目的包名,所有的基本組件都是在這個進(jìn)程中進(jìn)行,Application的onCreate方法會被執(zhí)行一次
。但是如果我們工程涉及到多進(jìn)程,那么就會出現(xiàn)Application的onCreate方法被多次執(zhí)行
情況。
解決oncreate方法多次被調(diào)用:
1、定義獲取進(jìn)程的方法
private String getProcessName(Context context) {
try {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
if (runningApps == null) {
return null;
}
for (ActivityManager.RunningAppProcessInfo proInfo : runningApps) {
if (proInfo.pid == android.os.Process.myPid()) {
if (proInfo.processName != null) {
return proInfo.processName;
}
}
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
2、在onCreate方法中進(jìn)行比對
@Override
public void onCreate() {
super.onCreate();
String processName = getProcessName(this);
if (processName!= null) {
String pkName = this.getPackageName();
//只有主進(jìn)程,才執(zhí)行后續(xù)邏輯
if(processName.equals(pkName)==false) {
return;
}
}
使用Application避免一些內(nèi)存泄漏(Memory Leak)
在Java中內(nèi)存泄漏是指某個(某些)對象已經(jīng)不在被使用應(yīng)該被GC回收,但有一個對象持有這個對象的引用而阻止這個對象被回收。
比如在項(xiàng)目中經(jīng)常用到單例模式,而很多單例是需要傳遞Context的,由于sInstance是一個static且強(qiáng)引用的,若此時傳遞Context的是xxxActivity.this,那么這個xxxActivity就不會被內(nèi)存回收,就會造成內(nèi)存泄漏。
解決辦法就是Context傳遞context.getApplicationContext()
ps 經(jīng)常導(dǎo)致內(nèi)存泄漏核心原因分析(跳轉(zhuǎn)連接)
以下內(nèi)容等待被編輯到指定位置
ps 經(jīng)常導(dǎo)致內(nèi)存泄漏核心原因分析(跳轉(zhuǎn)連接)
keeping a long-lived reference to a Context
上述是常見的內(nèi)存泄漏的提示,即持有一個context的對象,從而GC不能回收,為什么會有這樣的情況呢
- 一個View的作用域超出了所在的Activity的作用域,比如一個static的View或者把一個View cache到了application
- 某些與View關(guān)聯(lián)的Drawable的作用域超出了Activity的作用域.
- Runnable對象:比如在一個Activity中啟用了一個新線程去執(zhí)行一個任務(wù),在這期間這個Activity被系統(tǒng)回收了, 但Runnalbe的 任務(wù)還沒有執(zhí)行完畢并持有Activity的引用而泄漏,但這種泄漏一般來泄漏一段時間,只有Runnalbe的線程執(zhí)行完閉,這個 Activity又可以被正?;厥樟?。
- 內(nèi)存類的對象作用域超出Activity的范圍:比如定義了一個內(nèi)存類來存儲數(shù)據(jù),又把這個內(nèi)存類的對象傳給了其它Activity、Service等。因?yàn)閮?nèi)部類的對象會持有當(dāng)前類的引用,所以也就持有了Context的引用。
解決方法是如果不需要當(dāng)前的引用把內(nèi)部類寫成static或者把內(nèi)部類抽取出來變成一個單獨(dú)的類,或者作用域超出Activity的作用域。
Out Of Memery Error 在Android中每一個程序所分到的內(nèi)存大小是有限的,如果超過了這個數(shù)就會報(bào)Out Of Memory Error。 Android給程序分配的內(nèi)存大小與手機(jī)硬件有關(guān),以下是一些手機(jī)的數(shù)據(jù):
G1:16M Droid:24 Nexus One:32M Xoom:48Ms
所以盡量把程序中的一些大的數(shù)據(jù)cache到本地文件。以免內(nèi)存使用量超標(biāo)。
記得數(shù)據(jù)傳遞完成之后,把存放在application的HashMap中的數(shù)據(jù)remove掉,以免發(fā)生內(nèi)存的泄漏。