淺析Android Context

一:什麼是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,代碼如下:(以下代碼來自《第一行代碼》)

public class MyApplication extends Application{

	private static Context context;

	@override
	public void onCreate(){
		context = getApplicationContext();
	}

	public static Context getContext(){
		return context;
	}
}
    接下來我們需要告知系統,當程序啓動的時候應該初始化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.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章