標籤:android context getapplicationcontex 記憶體泄露 繼承關係
一:什麼是Context?
Context,sdk中的解釋如下:interface to global information about an application environment.This is an abstract class whose implementation is provided by the Android System.It allows access to application-specific resources and classes,as well as up-calls for application-level operations such as launching activities,broadcasting and receiving intents,etc.
簡單的總結為三條:
1.它描述的是一個應用程式的環境的資訊,可以被稱作為上下文。
2.該類是一個抽象類別,Android提供了該抽象類別的具體實作類別。
3.通過它我們可以擷取應用程式的資源和類,也包括採取一些應用層級的操作,例如,啟動一個Activity,發送廣播,接收Intent.
二:Context抽象類別的繼承關係
由我們可以看出,Activity,service,Application實則全為Context的子類。
三:Context執行個體的建立時機以及數目
通常來說,程式建立Context執行個體的時機為以下三種情況:
1.建立Application對象時,而且整個App共有一個Application對象。
2.建立Service對象時
3.建立Activity對象時
由上可知,一個應用程式中Context執行個體個數的計算公式為:
總Context數 = Service個數 + Activity個數 + 1(Application對應的Context執行個體)
四:Context的擷取方式以及全域擷取Context的技巧
因為Activity,Service本身就是一個context對象,所以在其中擷取Context非常簡單,但當脫離了這些與Context類有緊密關係的類時,我們該如何獲得呢?當然這也有許多方法可以獲得,但我在此給大家分享一種方法,定製一個自己的Application類,以便於管理程式內一些全域的狀態資訊,如Context。建立一個MyApplication繼承自Application,代碼如下:(以下代碼來自《第一行代碼》)
<span style="font-size:14px;">public class MyApplication{private static Context context;@overridepublic void onCreate(){context = getApplicationContext();}public static Context getContext(){return context;}}</span> 接下來我們需要告知系統,當程式啟動的時候應該初始化MyApplication而不是預設的Application類,操作也很簡單,修改AndroidManifest.xml檔案的<application>標籤下的內容:
<application android:name="com.example.hhw.MyApplication" ....></appliaction>
之後,你可以通過以下方式在你想用Context的任何地方得到它。
<span style="font-size:14px;">MyApplication.getContext();</span>
五:Activity,Application的Context以及記憶體泄露
首先,Activity的Context和Application的Context肯定不是一個東西,一個是當前活動的Context,它的生命週期僅限於此活動,一個是整個應用程式的Context,它的生命週期伴隨著整個程式,鑒於Activity的Context的特點,濫用它往往會造成記憶體泄露,如下代碼所示:
<span style="font-size:14px;">public class TestContext{private static TestContext testContext;private Context context;private TestContext(Context context){this.context = context;} public static synchronized TestContext getInstance(Context context){ if(null == testContext) testContext = new TestContext(context); return testContext; }}</span>
顯而易見,上述單例模式中textContext是強引用static類型,往往它的生命週期伴隨著整個應用程式,但你傳遞進來的Context若是一個Activity的,只要我們這個應用程式還活著,它就沒有辦法正常的回收,這就造成了記憶體的泄露。解決的方法很簡單,將初始化TestContext是傳遞的參數變為context.getApplicationContext()既可,因為用此方法獲得的是應用程式的context,因此就不用擔心記憶體泄露了。
public class TestContext{private static TestContext testContext;private Context context;private TestContext(Context context){this.context = context;} public static synchronized TestContext getInstance(Context context){ if(null == testContext) testContext = new TestContext(context.getApplicationContext()); return testContext; }}
既然如此的話,在能使用context的地方全部替換成context.getApplicationContext()不就皆大歡喜了嗎?很遺憾的來說,這樣不行,因為他們根本不是一個東西,它們的應用情境是不同的,並非所有的Activity的Context的情境,Application的Context依然可以,一下是我總結出來的一個表格,表示了它倆之間的應用情境:
| |
Application |
Activity |
| show a dialog |
NO |
YES |
| Layout Inflation |
NO |
YES |
| start an activity |
NO |
YES |
| Bild to a Service |
YES |
YES |
| Send a Broadcast |
YES |
YES |
| Register BrocastReceiver |
YES |
YES |
| start a service |
YES |
YES |
| load resource values |
YES |
YES |
其實我們只要把握住兩條原則即可:
1.凡是和UI相關的,都不建議使用Application的Context.
2..不要讓生命週期長的對象引用activity context,即保證引用activity的對象要與activity本身生命週期是一樣的,若不一樣,請考慮一下是否可以使用Application的Context.
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
淺析Android Context