Android Manifest.xml中application功能和重寫
android:name屬性是用來設定所有activity 屬於哪個application的,預設是android.app.Application。
當然也可以自己定義一個類,例如:
public class TestApplication extends Application {}
這個類的作用是為了放一些全域性的和一些上下文都要用到的變數和方法。
然後在AndroidManifest.xml中<application/>節點中新增android:name屬性
<application android:icon="@drawable/icon"
android:label="@string/app_name"
android:name=".TestApplication">
這樣就可以將預設的Application給設定成我們自定義的TestApplication
這樣處理的好處是:
繼承的話,當應用程式退出後其生命週期也跟著結束,
而用靜態類的話程式退出後不會立刻被gc回收,當你再次進入後會發現該靜態類儲存的資訊狀態是之前的。
有可能會導致程式不是你想要的初始化狀態。
PS:TestApplication一定要指明類域為public,否則執行時候會報錯找不到這個類。
即使寫成這樣:class TestApplication extends Application{}
也不可以,因為預設情況只是為包可見。
What is Application
Application和Activity,Service一樣是android框架的一個系統元件,當android程式啟動時系統會建立一個 application物件,用來儲存系統的一些資訊。通常我們是不需要指定一個Application的,這時系統會自動幫我們建立,如果需要建立自己
的Application,也很簡單建立一個類繼承 Application並在manifest的application標籤中進行註冊(只需要給Application標籤增加個name屬性把自己的 Application的名字定入即可)。
android系統會為每個程式執行時建立一個Application類的物件且僅建立一個,所以Application可以說是單例 (singleton)模式的一個類.且application物件的生命週期是整個程式中最長的,它的生命週期就等於這個程式的生命週期。因為它是全域性的單例的,所以在不同的Activity,Service中獲得的物件都是同一個物件。所以通過Application來進行一些,資料傳遞,資料共享 等,資料快取等操作。
Data passing between components using Application
假如有一個Activity A, 跳轉到 Activity B ,並需要推薦一些資料,通常的作法是Intent.putExtra() 讓Intent攜帶,或者有一個Bundle把資訊加入Bundle讓Intent推薦Bundle物件,實現傳遞。但這樣作有一個問題在 於,Intent和Bundle所能攜帶的資料型別都是一些基本的資料型別,如果想實現複雜的資料傳遞就比較麻煩了,通常需要實現 Serializable或者Parcellable介面。這其實是Android的一種IPC資料傳遞的方法。如果我們的兩個Activity在同一個 程序當中為什麼還要這麼麻煩呢,只要把需要傳遞的物件的引用傳遞過去就可以了。
基本思路是這樣的。在Application中建立一個HashMap<String,Object> ,以字串為索引,Object為value這樣我們的HashMap就可以儲存任何型別的物件了。在Activity A中把需要傳遞的物件放入這個HashMap,然後通過Intent或者其它途經再把這人索引的字串傳遞給Activity B ,Activity B 就可以根據這個字串在HashMap中取出這個物件了。只要再向下轉個型 ,就實現了物件的傳遞。
Data caching in Application
我一般會習慣在application中建立兩個HashMap<String,Object>一個用於資料的傳遞,一個用於快取一些資料。比如有一個Activity需要從網站獲取一些資料,獲取完之後我們就可以把這個資料cache到Application 當中,當頁面設定到其它Activity再回來的時候,就可以直接使用快取好的資料了。但如果需要cache一些大量的資料,最好是cache一些 (軟引用)SoftReference ,並把這些資料cache到本地rom上或者sd卡上。如果在application中的快取不存在,從本地快取查詢,如果本地快取的資料也不存在再從網 絡上獲取。
PitFalls
使用Application如果儲存了一些不該儲存的物件很容易導致記憶體洩漏。如果在Application的oncreate中執行比較 耗時的操作,將直接影響的程式的啟動時間。不些清理工作不能依靠onTerminate完成,因為android會盡量讓你的程式一直執行,所以很有可能 onTerminate不會被呼叫。
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到本地檔案。以免記憶體使用量超標。
Snippets
1,通過Application在兩個Activity間傳遞資料
記得資料傳遞完成之後,把存放在application的HashMap中的資料remove掉,以免發生記憶體的洩漏。
其實我們開發的每個android應用程式就是一個Appliction,定義這個類往往是在AndroidManifes.xml中用到。例如:
< application android:icon = "@drawable/icon" |
android:label = "@string/app_name" |
android:name = ".MyApplication" > |
public class MyApplication extends Application
{ |
} |
MyApplication類的作用是為了放一些全域性的和一些上下文都要用到變數和方法之類的。