1. 程式人生 > >Android 元件 — Activity (建立與啟動)

Android 元件 — Activity (建立與啟動)

Activity 簡介

 Activity 是應用程式的四大元件之一,為使用者提供一個互動介面,比如打電話、發簡訊、傳送郵件等。每一個Activity都會提供一個視窗用於繪製使用者介面。通常視窗都是全屏,但是也可以浮在其他的視窗之上。

 app一般由一個或者多個Activity鬆散耦合在一起。最常見的情況是,一個Activity被指定為“mian”Activity,作為使用者啟動app時最先進入的介面。Activity可以啟動其他的Activity介面來滿足不同德操作。每次開啟一個新的Activity時會先關閉當前的Activity,然後將其儲存在“Back Stack”(類似先進後出的棧結構),預設情況下,被關閉的Activity會被放在Back Stack中,當用戶按下返回鍵時,以前的Activity會從棧頂彈出並獲得使用者的焦點。(關於Back Stack的部分會在

Tasks and Back Stack文件中詳細討論)

 當一個Activity因為新開啟一個Activity是被關閉,他會將Activity狀態的變化通知Activity的“生命週期回撥”方法。Activity的生命週期被分為幾個狀態:creation、started、stopped、pause、resume、destroy,每個狀態會對應一個回撥方法。系統會在Activity狀態發生改變的時候回撥這些方法,這樣你就有機會指定一些適當的程式碼。舉個例子,當你關閉一個Activity的時候你必須釋放一些太好記憶體的物件,比如網路、資料庫連線等。當Activity恢復時,你可以再次申請那些必要的資源來恢復之前被中斷的操作。

 這篇文章剩餘的部分會討論如何建立和使用一個Activity,包括Activity生命週期的狀態切換,以及如何處理狀態的變換。

Activity的建立

 首先你需要建立一個子類來繼承Activity。在子類中需要實現回撥方法以提供給系統在不同的狀態下呼叫,其中最重要的兩個回撥函式如下:

這個方法你必須實現。系統在Activity被建立的時候會呼叫此方法。在此方法中你應用初始化Activity必須用到的資源。最終要的時候你需要呼叫setContentView()設定Layout檔案來填充你的使用者介面。
當用戶離開當前的介面時會呼叫此方法,雖然不一定會終止Activity,但是有可能此介面不會在恢復,所以你需要儲存一些使用者的設定,以保證使用者的設定生效。

 還有一些其他的生命週期回撥方法,你應該合理的運用這些回撥方法,保證在正不同Activity切換和Activity被異常中斷的情況下仍然有一個流暢的使用者體驗,稍後會在Managing the Activity Lifecycle 一節中詳細的討論所有的回撥方法。

實現使用者介面

 一個使用者介面由不同級別的檢視(view)組成—view是繼承於View類的物件。每一個檢視都控制者Activity視窗中的一個矩形區域,而且可以與使用者互動。舉個例子,一個檢視可能是一個按鈕,當用戶點選時可以觸發某個操作。

 Android 提供了許多現成的檢視(view),你可以用來設計和組織你layout(佈局)。“Widgets”是view的別稱,它提供了一個在螢幕視覺化的元素,比如一個按鈕(button)、文字框(Text filed)、單選框(checkbox)、或者僅僅是一副影象(image)。“Layout”繼承於ViewGroup,為view提供了一個特有的佈局模型,比如線性佈局(LinearLayout)、網格佈局(grid Layout)、相對佈局(relative Layout)。當然,你也可以直接繼承 View 和 類來建立自己的widget和layout,然後應用到Activity的佈局中。

 一般會在app的資原始檔中定義一個XML Layout檔案。通過這個方法,你可以將Activity的行為與使用者的介面分開維護。每一個佈局檔案都有一個ID,你可以呼叫setContentView(layout ID)方法為你的Activity設定佈局檔案,你也可以在程式碼中(分級式地)建立view並插入到ViewGroup中,然後將ViewGroup作為layout引數傳遞給setContentView()

 在AndroidManifest.xml中宣告Activity

為了保證系統能夠訪問你的Activity,你需要在AndroidManifest.xml檔案中進行宣告。宣告方式如下:開啟工程目中的AndroidManifest.xml檔案,在<application>元素中新增一個子元素<activity>:

<manifest ... > 
  <application ... > 
      <activity android:name=".ExampleActivity" /> 
      ... 
  </application ... > 
  ... 
</manifest >

<activity>元素下還可以增加其他屬性,比如增加一個標籤、定義Activity的風格或主題。android:name屬性是必須設定的,它指明瞭Activity的類名。一旦你釋出app,你的類名就不能隨意的更改,否則會破壞一些功能,比如已經建立好的app快捷方式,如果你更改了android:name,快捷方式就會失效。(read the blog post, Things That Cannot Change).

“intent filter”的使用

 AndroidManifest.xml檔案中,為了方便其他的app能夠啟用你的activity,可以在<activity>增加<intent-filter>元素。

 當你用Android SDK tools建立一個app時,它會自動為你建立一個放在“launcher” 類中的activity的存根,以便響應“main”action,inten filter的使用方式如下:

<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>標識了app的“main”入口,<category>表示activity會被放在系統的ApplicationLauncher中,以便使用者啟動(launch)這個activity。

如果你打算只在當前app中使用該activity,而且不允許其他app啟用該activity,那你就不需要任何intent filter。如同上面的例子,只能有一個activity的intent filter 能使用者“main”action和“launcher”category。你不需要其他app訪問的activity則不需要宣告intent filter,該activity所在的app只需要指定activity類名就可以啟動了。

 啟動Activity

你可以呼叫startActivity((Intent intent, Bundle options))來啟動其他的Activity,intent用於描述想要啟動的Activity。intent可以是明確指定啟動的Activity類名,或者描述你要啟動的動作(系統會根據你的描述為你選擇一個合適的Activity,甚至從不同app查詢也是有可能的)。intent也可以攜帶少量的資料傳遞給需要啟動的Activity。

 在Activity內部啟動當前app中的其他Activity可以直接在intent中指定類名,方式如下:

Intent intent = new Intent(this, SignInActivity.class); 
startActivity(intent);

然而,你的app執行的某些操作,比如打電話、發簡訊、檢視地圖,但是你的app可能沒有完成這些功能的Activity,這個時候你可以利用裝置上其他具備這些功能的Activity來完成這些操作。intent真正的價值在於,你只需要描述你想要做的操作,系統會自動為你匹配合適的Activity,如果存在相同功能的Activity的時候,會再提示使用者選擇。舉個例子,如果你允許使用者發郵件,你可以像下面這樣建立一個intent:

Intent intent = new Intent(Intent.ACTION_SEND); 
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); 
startActivity(intent);

putExtra中recipientArray是一個email 地址的字串,當帶有email功能的app響應這個intent的時候,它會解析recipientArray中的內容然後放到收件人的位址列裡。這種情況下,email 傳送後會再恢復你之前的Activity。 

Activity 的反饋機制

 有時候,你可能希望啟動的Activity完成操作後能回傳資料。這種情況下,你可以呼叫startActivityForResult()來啟動Activity(而不是呼叫startActivity())。為了能接收Activity處理的結果,你需要實現回撥方法:onActivityResult()。當被啟動的Activity推出後會返回一個intent給onActivityResult()

 舉個例子,可能你想要使用者選擇一個聯絡人,然後你的Activity就可以使用聯絡人資訊做一些事情。上程式碼:

private void pickContact() { 
    // Create an intent to "pick" a contact, as defined by the content provider URI 
    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 the request went well (OK) and the request was PICK_CONTACT_REQUEST 
    if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { 
        // Perform a query to the contact's content provider for the contact's name 
        Cursor cursor = getContentResolver().query(data.getData(), 
        new String[] {Contacts.DISPLAY_NAME}, null, null, null); 
        if (cursor.moveToFirst()) { // True if the cursor is not empty 
            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); 
            String name = cursor.getString(columnIndex); 
            // Do something with the selected contact's name... 
        } 
    } 
}