### Android Application類的介紹 ###
#### 相關參考文檔 ####
- [官方文檔(Java版本)](https://developer.android.google.cn/reference/android/app/Application.html)
- [android Application類的詳細介紹](http://blog.csdn.net/pi9nc/article/details/11200969)
- [Android Application類的介紹](http://blog.csdn.net/fankarl/article/details/52055147)
- [Android中Application類用法](http://www.cnblogs.com/renqingping/archive/2012/10/24/Application.html)
#### 類層次結構

#### 類的屬性及成員

#### 類概述
- 官網原文如下
> Base class for those who need to maintain global application state. You can provide your own implementation by specifying its name in your AndroidManifest.xml's `<application>` tag, which will cause that class to be instantiated for you when the process for your application/package is created.
- 對應譯文
> Application類是為了那些需要保存全局變量設計的基本類,你可以在AndroidManifest.xml的<application>標簽中進行自己的定義實現,這樣的結果是:當你的application或者包被建立的時候,這個類就會被實例化。
- 備注
> Note: There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), include Context.getApplicationContext() as a Context argument when invoking your singleton’s getInstance() method.
> 對應譯文:正常情況下來說,創建一個application子類并不是必須的,在很多情況下,單例模式在更多模塊化的方式下能起到相同的效果,如果單例需要全局context,可以利用Context.getApplicationContext()拿到Context對象從而引用單例的getInstance()方法。
#### 概括
1. Application其實可以說成是單例模式的一個類,并且application對象的生命周期肯定是整個程序中最長的,因為它的生命周期就等于整個程序的生命周期。
2. 因為application全局都是單例的,所以對于程序里所有的Activity、Service來說所獲得的application對象都是同一個,因此可以通過Application可以進行一些比如數據傳遞、數據共享、數據緩存等操作。
3. application是用來保存全局變量的,并且是在package創建的時候就跟著存在了。所以當我們需要創建全局變量的時候,不需要再像j2se那樣需要創建public權限的static變量,而直接在application中去實現。只需要調用Context的getApplicationContext或者Activity的getApplication方法來獲得一個application對象,再做出相應的處理。
#### 應用場景:
在Android中,可以通過繼承Application類來實現應用程序級的全局變量,這種全局變量方法相對靜態類更有保障,直到應用的所有Activity全部被destory掉之后才會被釋放掉。
#### Android Application對象必須掌握的七點
- [理解理解Application創建過程](http://gityuan.com/2017/04/02/android-application/)
- system_server進程創建application(點擊[查看大圖](https://i.imgur.com/Mn4hKRP.jpg))
- 
-
- app進程創建application(點擊[查看大圖](https://i.imgur.com/tRehPFk.jpg))
- 
#### 1:Application是什么?
1. Application和Activity,Service一樣,是android框架的一個系統組件,當android程序啟動時系統會創建一個 application對象,用來存儲系統的一些信息。通常我們是不需要指定一個Application的,這時系統會自動幫我們創建,如果需要創建自己 的Application,也很簡單創建一個類繼承 Application并在manifest的application標簽中進行注冊(只需要給Application標簽增加個name屬性把自己的 Application的名字定入即可)。
2. android系統會為每個程序運行時創建一個Application類的對象且僅創建一個,所以Application可以說是單例 (singleton)模式的一個類.且application對象的生命周期是整個程序中最長的,它的生命周期就等于這個程序的生命周期。因為它是全局 的單例的,所以在不同的Activity,Service中獲得的對象都是同一個對象。所以通過Application來進行一些,數據傳遞,數據共享 等,數據緩存等操作。
3. 啟動Application時,系統會創建一個PID,即進程ID,所有的Activity都會在此進程上運行。那么我們在Application創建的時候初始化全局變量,同一個應用的所有Activity都可以取到這些全局變量的值,換句話說,我們在某一個Activity中改變了這些全局變量的值,那么在同一個應用的其他Activity中值就會改變。
#### 2:通過Application傳遞數據
1. 假如有一個Activity A, 跳轉到 Activity B ,并需要推薦一些數據,通常的作法是`Intent.putExtra()` 讓Intent攜帶,或者有一個Bundle把信息加入Bundle讓Intent推薦Bundle對象,實現傳遞。但這樣作有一個問題在于,Intent和Bundle所能攜帶的數據類型都是一些基本的數據類型,如果想實現復雜的數據傳遞就比較麻煩了,通常需要實現 Serializable或者Parcellable接口。這其實是Android的一種IPC數據傳遞的方法。如果我們的兩個Activity在同一個進程當中為什么還要這么麻煩呢,只要把需要傳遞的對象的引用傳遞過去就可以了。
2. 基本思路是這樣的。在Application中創建一個HashMap,以字符串為索引,Object為value這樣我們的HashMap就可以存儲任何類型的對象了。在Activity A中把需要傳遞的對象放入這個HashMap,然后通過Intent或者其它途經再把這索引的字符串傳遞給Activity B ,Activity B就可以根據這個字符串在HashMap中取出這個對象了。只要再向下轉個型,就實現了對象的傳遞。
#### 3:Application數據緩存
我一般會習慣在application中建立兩個HashMap一個用于數據的傳遞,一個用于緩存一些數據。比如有一個Activity需要從網站獲取一些數據,獲取完之后我們就可以把這個數據cache到Application 當中,當頁面設置到其它Activity再回來的時候,就可以直接使用緩存好的數據了。但如果需要cache一些大量的數據,最好是cache一些 (軟引用)SoftReference,并把這些數據cache到本地rom上或者sd卡上。如果在application中的緩存不存在,從本地緩存查找,如果本地緩存的數據也不存在再從網絡上獲取。
#### 4:PitFalls(漢語:易犯的錯誤)
使用Application如果保存了一些不該保存的對象很容易導致內存泄漏。如果在Application的onCreate中執行比較耗時的操作,將直接影響的程序的啟動時間。清理工作不能依靠onTerminate完成,因為android會盡量讓你的程序一直運行,所以很有可能onTerminate不會被調用。
#### 5:MemoryLeak(內存泄漏)
- 在Java中內存泄漏是指,某個(某些)對象已經不再被使用,而是應該被gc所回收,但有一個對象持有這個對象的引用而阻止這個對象被回收。比如我們通常會這樣創建一個`View TextView tv = new TextView(this)`;這里的this通常都是Activity。所以這個TextView就持有著這個Activity的引用。下面看張圖 (Google IO 2011 ppt中抄得)
- 通常情況下,當用戶轉動手機的時候,android會重新調用OnCreate()方法生成一個新的Activity,原來的 Activity應該被GC所回收。但如果有個對象比如一個View的作用域超過了這個Activity(比如有一個static對象或者我們把這個View的引用放到了Application當中),這時候原來的Activity將不能被GC所回收,Activity本身又持有很多對象的引用,所以整個Activity的內存被泄漏了。
> 備注:經常導致內存泄漏核心原因:
keeping a long-lived reference to a Context.持有一個context的對象,從而gc不能回收。
- 情況如下:
1. 一個View的作用域超出了所在的Activity的作用域,比如一個static的View或者把一個View cache到了application當中 etc
**注意:內存:注意靜態的數據和緩存中的數據;注意釋放;**
2. 某些與View關聯的Drawable的作用域超出了Activity的作用域。
3. Runnable對象:比如在一個Activity中啟用了一個新線程去執行一個任務,在這期間這個Activity被系統回收了,但Runnalbe的任務還沒有執行完畢并持有Activity的引用而泄漏,但這種泄漏一般來泄漏一段時間,只有Runnalbe的線程執行完閉,這個Activity又可以被正常回收了。
4. 內部類的對象作用域超出Activity的范圍:比如定義了一個內存類來存儲數據,又把這個內部類的對象傳給了其它Activity 或者Service等。因為內部類的對象會持有當前類的引用,所以也就持有了Context的引用。解決方法是如果不需要當前的引用,把內部類寫成static或者把內部類抽取出來變成一個單獨的類,或者把避免內部對象作用域超出Activity的作用域。**`out Of Memery Error `**:在android中每一個程序所分到的內存大小是有限的,如果超過了這個數就會報Out Of Memory Error。 android給程序分配的內存大小與手機硬件有關,以下是一些手機的數據:
G1:16M Droid:24 Nexus One:32M Xoom:48Ms
所以盡量把程序中的一些大的數據cache到本地文件。以免內存使用量超標。
記得數據傳遞完成之后,把存放在application的HashMap中的數據remove掉,以免發生內存的泄漏。
#### 6:生命周期
- **onCreate()** 在創建應用程序時創建
- **onTerminate()** 當終止應用程序對象時調用,不保證一定被調用,當程序是被內核終止以便為其他應用程序釋放資源,那么將不會提醒,并且不調用應用程序的對象的onTerminate方法而直接終止進程
- **onLowMemory()** 當后臺程序已經終止資源還匱乏時會調用這個方法。好的應用程序一般會在這個方法里面釋放一些不必要的資源來應付當后臺程序已經終止,前臺應用程序內存還不夠時的情況。
- **onConfigurationChanged()** 配置改變時觸發這個方法
#### 備注
**application 被殺死的情況分析**:
Android系統將盡量長時間地保持應用進程,但為了新建進程或運行更重要的進程,最終需要清除舊進程來回收內存。為了決定在內存較低的時候殺掉哪個進程, Android會根據運行在這些進程內的組件及他們的狀態把進程劃分成一個”重要程度層次”. 其重要的程度按以下規則排序,必要時,系統會首先消除重要性最低的進程,然后是清除重要性稍低一級的進程,依此類推,以回收系統資源。:
前臺進程的重要性最高,依次遞減,空進程的重要性最低
Android中對于內存的回收,主要依靠Lowmemorykiller來完成,是一種根據閾值級別觸發相應力度的內存回收的機制。
可以參考文章[Android進程生命周期與ADJ](http://www.hmoore.net/alex_wsc/androidsystem/403696)
- 1:**Foreground process 前臺進程**
可以是一個持有運行在屏幕最前端并與用戶交互的Activity的進程(onResume方法被調用時),也可以是持有一個正在運行的IntentReceiver(也就是說他正在執行自己的onReceiveIntent方法)的進程.
在系統中, 只會有少數這樣的進程, 并且除非內存已經低到不夠這些進程運行, 否則系統不會主動殺掉這些進程. 這時, 設備通常已經達到了需要內存整理的狀態, 所以殺掉這些進程是為了不讓用戶界面停止響應.
擁有下列特性的進程都是**前臺進程**
- 擁有用戶正在交互的 Activity(已調用onResume())
- 擁有某個 Service,后者綁定到用戶正在交互的 Activity
- 擁有正在“前臺”運行的 Service(服務已調用 startForeground())
- 擁有正執行一個生命周期回調的 Service(onCreate()、onStart() 或 onDestroy())
- 擁有正執行其 onReceive() 方法的 BroadcastReceiver
- 2:**Visible process 可見進程**
是持有一個被用戶可見, 但沒有顯示在最前端 (onPause方法被調用時) 的Activity的進程.
舉例來說, 這種進程通常出現在一個前端Activity以一個對話框出現并保持前一個Activity可見時.
這種進程被系統認為是極其重要的, 并且通常不會被殺掉, 除非為了保持所有前端進程正常運行,而不得不殺掉這些可見進程
如下進程都是可見進程
- 擁有不在前臺、但仍對用戶可見的 Activity(已調用onPause())。
- 擁有綁定到可見(或前臺)Activity 的 Service
- 3:**Service process 服務進程**
是持有一個Service的進程, 該Service是由startService()方法啟動的,
這一進程運行的service ,是那些已執行startService() 方法且不屬于前面兩個高類別的服務
盡管服務進程與用戶所見內容沒有直接關聯,盡管這些進程用戶不能直接看到, 但是通常他們做的工作,用戶是十分關注的(例如,在后臺播放mp3或是在后臺下載上傳文件),所以,除非為了保持所有的前端進程和可視進程正常運行外,系統是不會殺掉服務進程的.
如下進程
- 正在運行startService()方法啟動的服務,且不屬于上述兩個更高類別進程的進程
- 4:**Background process 后臺進程**
是持有一個不再被用戶可見的Activity(onStop()方法被調用時)的進程.
后臺進程對用戶體驗沒有直接影響,系統可能隨時終止它們,以回收內存供前臺進程、可見進程或服務進程使用
這些進程不會直接影響用戶體驗. 加入這些進程已經完整的,正確的完成了自己的生命周期(訪問Activity查看更多細節), 系統會在為前三種進程釋放內存時隨時殺掉這些后臺進程.
通常會有很多的后臺進程在運行, 所以這些進程被存放在一個LRU列表中, 以保證在低內存的時候, 最近一個被用戶看到的進程會被最后殺掉.
如果一個Activity實現其生命周期方法正確,并保存其當前狀態,殺死它的進程將不會對用戶體驗產生可見的效果,因為當用戶導航回到該Activity,該Activity恢復它的所有可見的狀態。看Activities文檔信息的保存和恢復狀態。
如下進程
- 對用戶不可見的Activity的進程(已調用Activity的onStop()方法)
- 5:**Empty process 空進程**
是沒有持有任何活動應用組件的進程.
保留這種進程的唯一理由是為了提供一種緩存機制, 縮短他的應用下次運行時的啟動時間. 就其本身而言, 系統殺掉這些進程的目的是為了在這些空進程和底層的核心緩存之間平衡整個系統的資源. 即:為使總體系統資源在進程緩存和底層內核緩存之間保持平衡,系統往往會終止這些進程。
當需要給一個進程分類的時候, 系統會在該進程中處于活動狀態的所有組件里,挑選一個重要等級最高作為分類依據. 查看Activity, Service,和IntentReceiver的文檔, 了解每個組件在進程整個生命周期中的貢獻. 每一個classes的文檔詳細描述他們在各自應用的生命周期中所起得作用.
如下進程
- 不含任何活動應用組件的進程
**備注**:
- 一個進程可以有較高級別的Android的優先級,基于它的重要性。例如,如果一個進程開啟了 一個service 和一個可見的activity,這個進程的將作為一個可見的過程,不是一個服務過程。
- 此外,一個進程的排名可能會增加,因為其他的流程都依賴于它的一個過程,所以另一個進程永遠不能被排名低于這個過程中,服務。 例如,如果一個ContentProvider過程中的服務進程B中的客戶端或服務過程中,如果A是必然進程B中的一個組件,進程A總是被認為至少是同樣重要于進程B
因為一個進程運行服務的過程與背景活動,發起一項活動,可能會做一個長期運行的操作,操作以及啟動服務 ,而不是簡單地創建一個工作線程,特別是如果操作將可能高于排名經久活動。 例如,一個活動的圖片上傳到一個網站,應該啟動一個服務執行上傳,因此可以繼續在后臺上傳,即使用戶離開活動。 使用服務保證該操作將至少有“服務進程”的優先級,不管發生了什么活動。 廣播接收機應采用服務,而不是簡單地把在一個線程中耗時的操作,這是一樣的道理。
#### Application 的Context
1. 它描述的是一個應用程序環境的信息,即上下文。
2. 該類是一個抽象(abstract class)類,Android提供了該抽象類的具體實現類(后面我們會講到ContextIml類)。
3. 通過它我們可以獲取應用程序的資源和類,也包括一些應用級別操作,例如:啟動一個Activity,發送廣播、接受Intent信息等。
4. 類Context的類層次結構圖

更深層級的結構圖(部分)[大圖點擊這里](https://i.imgur.com/ZGHGF26.jpg)

#### Application類的實現 ####
- 1.繼承Application類,并重寫onCreate()方法
> 注:繼承Application類,主要重寫里面的onCreate()方法(**android.app.Application包的onCreate()才是真正的Android程序的入口點**),就是創建的時候,初始化變量的值。然后在整個應用中的各個文件中就可以對該變量進行操作了。
- 2.清單文件中配置自定義的Application
- 3.在程序中使用自定義類
> 注:只需要調用Context的 getApplicationContext或者Activity的getApplication方法來獲得一個Application對象,然后再得到相應的成員變量即可。它是代表我們的應用程序的類,使用它可以獲得當前應用的主題和資源文件中的內容等,這個類更靈活的一個特性就是可以被我們繼承,來添加我們自己的全局屬性。
### **總結來說**
**Application主要有以下3點作用**:
1. 整個程序的入口
2. 為一些第三方框架做一些初始化的工作
3. 為整個應用程序的其他模塊提供上下文
- 前言
- Android系統的體系結構
- Dalvik VM 和 JVM 的比較
- Android 打包應用程序并安裝的過程
- Android ADB工具
- Android應用開發
- Android UI相關知識總結
- Android 中window 、view、 Activity的關系
- Android應用界面
- Android中的drawable和bitmap
- AndroidUI組件adapterView及其子類和Adapter的關系
- Android四大組件
- Android 數據存儲
- SharedPreference
- Android應用的資源
- 數組資源
- 使用Drawable資源
- Material Design
- Android 進程和線程
- 進程
- 線程
- Android Application類的介紹
- 意圖(Intent)
- Intent 和 Intent 過濾器(Google官網介紹)
- Android中關于任務棧的總結
- 任務和返回棧(官網譯文)
- 總結
- Android應用安全現狀與解決方案
- Android 安全開發
- HTTPS
- 安卓 代碼混淆與打包
- 動態注入技術(hook技術)
- 一、什么是hook技術
- 二、常用的Hook 工具
- Xposed源碼剖析——概述
- Xposed源碼剖析——app_process作用詳解
- Xposed源碼剖析——Xposed初始化
- Xposed源碼剖析——hook具體實現
- 無需Root也能Hook?——Depoxsed框架演示
- 三、HookAndroid應用
- 四、Hook原生應用程序
- 五、Hook 檢測/修復
- Android 應用的逆向與加固保護技術
- OpenCV在Android中的開發
- Android高級開發進階
- 高級UI
- UI繪制流程及原理
- Android新布局ConstraintLayout約束布局
- 關鍵幀動畫
- 幀動畫共享元素變換
- Android異步消息處理機制完全解析,帶你從源碼的角度徹底理解
- Android中為什么主線程不會因為Looper.loop()里的死循環卡死?
- 為什么 Android 要采用 Binder 作為 IPC 機制?
- JVM 中一個線程的 Java 棧和寄存器中分別放的是什么?
- Android源碼的Binder權限是如何控制?
- 如何詳解 Activity 的生命周期?
- 為什么Android的Handler采用管道而不使用Binder?
- ThreadLocal,你真的懂了嗎?
- Android屏幕刷新機制