深度解析Android Activity初探
Activity概述
一個應用當中通常有若干個關系松散的activities組成。通常情況下,一個應該中有一個activity是主activity,它會在應用程序加載時展現(xiàn)出來,之后每個activity都有機會啟動其他activity,從而產(chǎn)生不同的動作。每當一個新的activity啟動的時候,它的前一任就會停下來,這時系統(tǒng)將前任放在一個棧(后臺棧)中。這個后臺棧遵循先進后出原則,所以當用戶對當前activity完成操作并按后退鍵時,原來棧中的activity就會從棧中彈出,恢復執(zhí)行。(我們會在任務和后臺棧中詳細討論后臺棧)
新activity啟動,舊activity停止,這些操作會通過調用activity的生命周期回調函數(shù)來進行通知。對于activity來說,它可能會收到很多回調,這些回調會在系統(tǒng)創(chuàng)建、停止、恢復或者銷毀一個activity時調用,這樣,activity就有機會感知變化進行在相應的回調中做出正確的處理。例如,當activity停止時,它應該釋放掉所有的大型對象,比如說網(wǎng)絡連接或數(shù)據(jù)庫連接。當activity恢復執(zhí)行時,可以重新獲取需要的資源并從中斷處重新運行。這些狀態(tài)的變化就是一個activity的生命周期。
創(chuàng)建一個Activity
創(chuàng)建一個Activity,必須要繼承Activity或者是繼承它相應的子類。在我們的子類當中,還需要實際一系列與生命周期轉化密切相關的接口函數(shù),比如說創(chuàng)建、停止、恢復或銷毀等回調接口。最重要的兩個回調函數(shù)是:
onCreate()
必須要實現(xiàn)的方法。當我們的Activity創(chuàng)建的時候,系統(tǒng)會調用此方法。在我們實現(xiàn)當中,需要初始化activity當中重要的組件。需要強調的是,在這個方法里,需要調用setContentView()來為activity的用戶界面調用布局。
onPause()
當用戶離開activity的時候,系統(tǒng)會調用這個函數(shù)。用戶可能不再會回來調用此activity,因此需要在本方法中把需要永久存儲的數(shù)據(jù)進行提交。
除了這兩個方法之外,在activity整個生命周期中還有很多回調方法需要關注。在后面我們會討論其他回調方法的作用。
創(chuàng)建一個用戶界面
Activity的用戶界面是由View來控制的。每個view控制著一片矩形區(qū)域并會對用戶的操作進行反饋。例如,一個view可能是一個按鈕,當用戶按下時,它會觸發(fā)一個事件。
Android系統(tǒng)提供了不少內置的view,我們可以用它們來設計我們的布局。"Wedgets"是一類可以顯示的views,比如說button,textfiled,checkbox或者image。"Layouts"是從ViewGroup繼承出來的類,它可以提供一種固定的布局模式,比如說linear layout,grid layout,或者relative layout。我們當然還可以繼承View和ViewGroup來實現(xiàn)自己的控件和布局。
使用views最常見的方式是在資源文件中的XML中定義它。這種方式可以使設計和行為的源代碼分開。我們可以通過調用setContentView()來為Activity設置布局。不過,我們也可以在代碼中添加Views,首先往ViewGroup中插入相應的Views,再將ViewGroup的根元素傳遞給setContentView()即可。
在manifest中聲明activity
必須在manifest文件中聲明activity,不然系統(tǒng)可以無法訪問我們的activity。步驟是,打開manifest文件,為<application>元素添加一個叫<activity>的子元素。
java代碼:
- <manifest ... >
- <application ... >
- <activity android:name=".ExampleActivity" />
- </application ... >
- </manifest >
這里還可以定義其他一些屬性,比如說定義標簽,圖標或者是UI的樣式等。使用intent filters 一個Activity可以具有多個intent filters(具體方式是在配置文件中聲明<intent-filter>),這樣可以方便其他activity訪問。可以理解成一個能力描述符,用來標識自己有哪些處理能力,當其他activity需要處理相應請求時,可以找到這個activity。
當使用Android SDK工具創(chuàng)建一個新的應用時,工具會自動幫我們創(chuàng)建一個filter,它的樣式如下:
java代碼:
- <activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
<action>元素說明這是應用程序的"main"入口。<category>元素表示該activity會被記錄在系統(tǒng)的啟動器當中(允許用戶啟動這個activity)。如果我們不想讓自己的應用被其他應用訪問的話,就無需再多聲明fileters了。在一個應用當中只有一個activity的filter可以有main action和launcher category。對于沒有聲明filters的activities,可以通過在intent中明確指出要調用的activity的類來啟動它。
如果我們想讓我們的activity接收其他activity的訪問并返回給對方結果的話,我們必須額外地再添加filters。對于我們想要回復的filters,我們必須在<intnent-filter>下面添加<action>元素,也可以選擇性地包含<category>元素和<data>元素。
欲知更多關于intents的情況,啟動Activity 可以通過調用startActivity()來啟動另外一個Activity,只需要傳遞相應的Intent參數(shù)描述被啟動項即可。Intent可以描述需要啟動的Activity,也可以描述啟動時需要的動作,還可以帶有少量的數(shù)據(jù)。當工作在自己的應用當中時,我們經(jīng)常需要啟動某個activity。這時,我們可以在intent當中指定要啟動的activity的類名。例如,我們想啟動一個類名為SignInActivity的activity,會使用如下代碼:
java代碼:
- Intent intent = new Intent(this, SignInActivity.class);
- startActivity(intent);
如果我們的應用還想做一些額外動作,比如說發(fā)送郵件、發(fā)送短信等。但可能我們的應用本身不具備這樣的功能,這時我們就要請求系統(tǒng)當中有這種能力的應用來幫我們。做這件事情比較簡單,我們只需要創(chuàng)建一個intent,設置我們想要執(zhí)行的動作,設置需要的數(shù)據(jù),然后發(fā)送出去即可。這時,如果系統(tǒng)當中有多個應用可以提供這些功能,系統(tǒng)會提示用戶去選擇一個應用。具體代碼如下:
java代碼:
- Intent intent = new Intent(Intent.ACTION_SEND);
- intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
- startActivity(intent);
為EXTRA_EMAIL添加的數(shù)據(jù)是一個字符串數(shù)組,其中包含郵件列表。當郵件應用回應這個intent時,它會讀取數(shù)組中的地址,然后設置郵件格式,發(fā)送郵件。以需要返回結果的方式啟動Activity有時,我們可能需要從我們啟動的activity當中獲取結果。這時,我們在啟動activity時就要調用startActivityForResult()方法。然后,我們在哪接收返回的數(shù)據(jù)呢?按照android的習慣,此時我們需要實現(xiàn)一個回調接口onActivityResult()。當我們啟動的activity完成時,它會以intent的形式在onActivityResult()中返回。
例如,我們需要用戶去選擇一個聯(lián)系人,然后再對這些聯(lián)系人做一些操作。下面的代碼演示了這個過程:
java代碼:
- private void pickContact(){
- Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
- startActivityForResult(intent, PICK_CONTACT_REQUEST);
- }
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
- Cursor cursor = getContentResolver().query(data.getData(), new String[] {Contacts.DISPLAY_NAME}, null, null, null);
- if (cursor.moveToFirst()) {
- int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
- String name = cursor.getString(columnIndex);
- }
- }
- }
【編輯推薦】