1. 程式人生 > >Context-----Activity,Application之間的交流使者

Context-----Activity,Application之間的交流使者

二 .Context的型別      Context的型別有兩種,一種是Activity-Context,另一種是Application-Activity,這兩種的區別就在於它們的生命週期不一樣,一個是隨著Activity的銷燬而銷燬,另一個是伴隨整個Application,鑑於我們以前學習java,C++這些語言的經驗,都會意識到,這些生命週期的不同可能會導致不同行為以及一些錯誤,這些都會在接下來講到,因為它們是我們使用Context必須注意的。 1.Application-Context    這個之所以先講,是因為這個比較麻煩,在於它的獲取需要通過一些手段。    Application-Context的生命週期是整個應用,所以,對於它的使用必須慎重,大部分情況下都要避免使用它,因為它會導致記憶體洩露的問題。我們先來舉個例子,如果我們現在在一個Activity中引入一個Application-Context,那麼,當我們這個Activity關閉的時候,這個Application-Context是不會消失的,因為它的生命週期要比我們的Activity長,如果只是一些用來計算的資料還好,但是如果這個Context與我們的Activity的建立有關,或者與我們在Activity要銷燬的資源比如圖片資源有關,那麼,問題就大條了!因為我們的Activity或圖片就不能正常銷燬,因為它與Application-Context相關聯,如果不能正常的釋放掉與它們相關的記憶體,就會出現所謂的記憶體洩露的問題。這種問題有時候是非常隱晦的,以至於我們根本無法察覺到,所以我們必須遵守相關的使用原則。       現在我們以一個例子來示例如何獲得Application-Context。       要想獲得Application-Context,我們可以先宣告一個Application的子類。   
class
A extends Application{}

      現在,我們在這個類中新增一些東西來證明可以通過Context來獲得A的相關資源和方法。這次我們使用一個Toast。

      首先,是在我們的類A裡新增以下的內容:

      String s = "hello";public String getString(String str){             s = str;return s;      }

      然後再在我們的Activity B中嘗試取用A的資料和方法:     

       A a = (A)getApplicationContext();       String s 
= a.s; s = a.getString("hello word"); Toast.makeText(this, s, Toast.LENGTH_LONG).show();

     然後我們還必須注意在我們的mainfest檔案中註冊我們的application:

 <application android:name=".A"></application>

     注意,我們的mainfes始的at檔案中一開pplication是沒有名字的,因為我們一般都只是啟動一個Activity,而不是一個application,所以,可以將我們這個application的名字註冊為繼承自Application的子類A,這樣才能正常顯示出一個Toast出來。如果沒有這麼做,就可能報出這樣的錯誤:android.app.Application cannot be cast to A。

      在上面的例子中可以看到,通過一個Application的子類就能在我們的Activity中呼叫它的資源和方法,但是其實完全可以不用這樣做,宣告一個class,然後new一個例項同樣可以做到這點,但是這裡只是想要大家明白,Context的確可以傳遞相關類的引用,並且通過這個引用來獲取相關類的資源和方法,而且這個Context甚至可以轉化為具體的子類,我們的getApplicationContext()返回的其實是一個Context,之所以能將它轉換為A,是因為Context傳遞的就是Application-Context,它是一個Application型別的,而類A是Application的子類,父類轉化為子類,這裡就會有個疑問,就是我們的父類是不可以強制轉化為子類的,因為子類可能有父類沒有的方法,這樣的轉化就會出現問題,但是,我們也知道,可以將子類的引用轉化為父類,因為父類的引用是可以指向子類的,所以這裡是想說明我們的Context真的是一個引用。

      Application-Context的生命週期為整個Application,所以如果是一些需要在整個應用期間都存在的資源,我們可以將它放進一個Application-Context中,然後通過獲取這個Context來使用它們。

2.Activity-Context       正如上面講的一樣,這個Context的生命週期是和得到它的引用的Activity一樣長,如果這個Activity結束了,那麼,這個Context也會得到釋放。它並不像我們上面的Application-Context需要特意去獲得,可以在一個Activity中使用this就可以獲得當前Activity的Context。還是拿上面例子中的Toast.makeText(this, s, Toast.LENGTH_LONG).show(),其中的this就是當前的Activity-Context,但是,一味的使用this是很危險的,我們要注意的就是,在匿名內部類如果單純只是使用this是會出錯的,因為內部類中使用this得到的是內部類的物件引用,而不是我們要得到的外部類的引用,於是,這時候就必須使用類名.this這種方式,這種做法在按鈕的事件監聽中是特別要注意的。   3.使用規則      因為使用Activity-Cntext會出現記憶體洩露的危險,所以我們一般都是使用Application-Context。下面就是這兩者的使用規則:     (1)不要讓生命週期長的物件引用Activity-Context,保證引用要與Ativity本身生命週期是一樣的,對於生命週期長的物件,使用Application-Context 。      如果你想要在某個Activity的介面上顯示某個元件,比如說Toast,那麼,請把你的Activity的Context作為引數傳給Toast,這樣就能將你的Activity和Toast關聯起來,但是,如果你想要在一個Activity中設定好你的Toast,然後再在另一個Activity中顯示,記住,你可以有兩種選擇,一種,就是通過我們的Intent:     
      Intent intent = new Intent(Activity1.this, Activity2.class);      startActivity(intent);

      這個Activity1就是我們要顯示Toast的Activity,而Acticity2就是我們設定Toast的Activity。

      但是,如果想要在Activity1中呼叫Toast.show(),接受Activity2中返回的Toast的話,那麼,使用預設的樣式是非常簡單的,如果你真的想要使用自定義的格式,自定義一個佈局檔案Toast.xml,那麼,請在你的Activity1中寫下這幾句:      
      LayoutInflater layout = getLayoutInflater();      View view = layout.inflate(R.layout.toast, null);  

      記住,必須是在setContentView()之後進行切換,不然就會報錯,而且,必須是在你要顯示的Activity的setContentView(),如果你放在Activity2中的setContentView()也是會出錯,就是空指標,因為我們的layout的元素只有在setContentView()之後才開始分配記憶體,而且我們只是呼叫Activity2的方法而已,並沒有啟動Activity2,這點必須注意。