1. 程式人生 > >Android Context介紹

Android Context介紹

Context型別

我們知道,Android應用都是使用Java語言來編寫的,那麼大家可以思考一下,一個Android程式和一個Java程式,他們最大的區別在哪裡?劃分界限又是什麼呢?其實簡單點分析,Android程式不像Java程式一樣,隨便建立一個類,寫個main()方法就能跑了,而是要有一個完整的Android工程環境,在這個環境下,我們有像Activity、Service、BroadcastReceiver等系統元件,而這些元件並不是像一個普通的Java物件new一下就能建立例項的了,而是要有它們各自的上下文環境,也就是我們這裡討論的Context。可以這樣講,Context是維持Android程式中各元件能夠正常工作的一個核心功能類。

下面我們來看一下Context的繼承結構:

Context的繼承結構還是稍微有點複雜的,可以看到,直系子類有兩個,一個是ContextWrapper,一個是ContextImpl。那麼從名字上就可以看出,ContextWrapper是上下文功能的封裝類,而ContextImpl則是上下文功能的實現類。而ContextWrapper又有三個直接的子類,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一個帶主題的封裝類,而它有一個直接子類就是Activity。

那麼在這裡我們至少看到了幾個所比較熟悉的面孔,Activity、Service、還有Application。由此,其實我們就已經可以得出結論了,Context一共有三種類型,分別是Application、Activity和Service。這三個類雖然分別各種承擔著不同的作用,但它們都屬於Context的一種,而它們具體Context的功能則是由ContextImpl類去實現的。

那麼Context到底可以實現哪些功能呢?這個就實在是太多了,彈出Toast、啟動Activity、啟動Service、傳送廣播、操作資料庫等等等等都需要用到Context。由於Context的具體能力是由ContextImpl類去實現的,因此在絕大多數場景下,Activity、Service和Application這三種類型的Context都是可以通用的。不過有幾種場景比較特殊,比如啟動Activity,還有彈出Dialog。出於安全原因的考慮,Android是不允許Activity或Dialog憑空出現的,一個Activity的啟動必須要建立在另一個Activity的基礎之上,也就是以此形成的返回棧。而Dialog則必須在一個Activity上面彈出(除非是System Alert型別的Dialog),因此在這種場景下,我們只能使用Activity型別的Context,否則將會出錯。

和UI相關的方法基本都不建議或者不可使用Application。實際上,只要把握住一點,凡是跟UI相關的,都應該使用Activity做為Context來處理;其他的一些操作,Service,Activity,Application等例項都可以,當然了,注意Context引用的持有,防止記憶體洩漏。

Context數量

那麼一個應用程式中到底有多少個Context呢?其實根據上面的Context型別我們就已經可以得出答案了。Context一共有Application、Activity和Service三種類型,因此一個應用程式中Context數量的計算公式就可以這樣寫:

Context數量 = Activity數量 + Service數量 + 1  

上面的1代表著Application的數量,因為一個應用程式中可以有多個Activity和多個Service,但是隻能有一個Application。

Android獲取各種Context

1. getApplicationContext() :

這個函式返回的這個Application的上下文,所以是與app掛鉤的,所以在整個生命週期裡面都是不變的,這個好理解,但是使用的時候要注意,該context是和引用的生命週期一致的,所以和activity生命週期掛鉤的任務不要使用該context,比如網路訪問,防止記憶體洩露

2. getBasecontext():

stackoverflow上面寫的是,這個函式不應該被使用,用Context代替,而Context是與activity相關連,所以當activity死亡後可能會被destroyed,我舉個我自己寫的例子


public Dialog displayDialog(int choice) {  
    switch(choice){  
    case 0:  
      AlertDialog aDialog = new AlertDialog.Builder(this)  
      .setIcon(R.drawable.ic_launcher)  
      .setTitle("Hello World")  
      .setPositiveButton("OK", new DialogInterface.OnClickListener() {  
   
      @Override 
      public void onClick(DialogInterface arg0, int arg1) {  
        Toast.makeText(getBaseContext(), "OK clicked", Toast.LENGTH_SHORT).show();  
      }  
    });
  }
}

這個例子中的getBaseContext()就不能被this代替,因為上面的this返回的是這個activity的context,而在這個onClick函式中如果使用this的話,則返回的是這個AlertDialog的context,所以要使用的是當前activity名.this 去使用,比如當前activity為 TestActivity,那麼在裡面就是用TestActivity.this即可.

 3. getApplication():

getApplication只能被Activity和Services使用,雖然在現在的Android的實現中,getApplication和getApplicationContext返回一樣的物件,但也不能保證這兩個函式一樣(例如在特殊的提供者來說),所以如果你想得到你在Manifest檔案裡面註冊的App class,你不要去呼叫getApplicationContext,以為你可能得不到你所要的app例項(你顯然有測試框架的經驗)。。。。

4. getParent() :

返回activity的上下文,如果這個子檢視的話,換句話說,就是當在子視圖裡面呼叫的話就返回一個帶有子檢視的activity物件,一目瞭然。。。

5.getActivity():

在fragment中使用,返回該fragment所依附的activity上下文

6.this

記住Activity,Service類,Application類是繼承自Context類的,所以在有的時候需要上下文,只需要使用this關鍵字即可,但是有的時候再執行緒裡面,this關鍵字的意義就改變了,但這個時候如果需要上下文,則需要使用 類名.this,這樣就可以了

  • 使用this, 說明當前類是context的子類,一般是activity application等;

        this:代表當前,在Activity當中就是代表當前的Activity,換句話說就是Activity.this在Activity當中可以縮寫為this.

        Activity.this的context 返回當前activity的上下文,屬於activity ,activity 摧毀他就摧毀

  • 使用getApplicationContext 取得的是當前app所使用的application,這在AndroidManifest中唯一指定。意味著,在當前app的任意位置使用這個函式得到的是同一個Context;

        getApplicationContext(): 返回應用的上下文,生命週期是整個應用,應用摧毀,它才摧毀。

  • 使用getContext獲取的是當前物件所在的Context, Context通常翻譯成上下文,我通常當成場景來理解。
  • getApplication():andorid 開發中共享全域性資料;
  • getBaseContext() 返回由建構函式指定或setBaseContext()設定的上下文

我們在平時的開發中,有時候可能會需要一些全域性資料,來讓應用中得所有Activity和View都能訪問到,大家在遇到這種情況時,可能首先會想到自己定義一個類,然後建立很多靜態成員,不過andorid已經為我們提供了這種情況的解決方案:在Android中,有一個名為Application的類,我們可以在Activity中使用getApplication(),方法來獲得,它是代表我們的應用程式的類,使用它可以獲得當前應用的主題,資原始檔中的內容等,這個類更靈活的一個特性就是可以被我們繼承,來新增我們自己的全域性屬性。