Android應用程式的四大組件分別是Activity、Service、BroadcastReceiver和ContentProvider。本文將主要對Activity做一個較全面的總結,Service和BroadcaseReceiver也將在隨後的博文中分別進行介紹。有關ContentProvider的使用方法可以參閱博文《Android學習筆記37:使用Content Providers方式共用資料》。
1.Activity註冊
Activity是Android中最常見的組件,每個Activity都相當於一個螢幕,為使用者提供了進行互動的可視化介面。應用程式可以根據需要包含一個或多個Activity,這些Activity都繼承自android.app包下的Activity類,並且這些Activity之間的運行是相互獨立的。
應用程式中使用到的所有Activity都需要在AndroidManifest.xml檔案中進行註冊。註冊Activity時,需要使用<Activity></Activity>標籤,該標籤位於<application></application>中,具體位置如下:
1 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 package="com.example.android_datastorage_sqlite" 3 android:versionCode="1" 4 android:versionName="1.0" > 5 6 <application 7 android:icon="@drawable/ic_launcher" 8 android:label="@string/app_name" 9 android:theme="@style/AppTheme">10 11 <activity12 android:name=".MainActivity"13 android:label="@string/title_activity_main" >14 <intent-filter>15 <action android:name="android.intent.action.MAIN" />16 <category android:name="android.intent.category.LAUNCHER" />17 </intent-filter>18 </activity>19 20 </application>21 22 </manifest>
1.1 <Activity>標籤的屬性值
在<Activity></Activity>標籤中,有以下一些常用的屬性值可以設定:
(1)android:name,該屬性值用於表示自訂的Activity子類名稱,其值可以是子類的全稱類名“com.example.android_datastorage_sqlite.MainActivity”,也可以以“.”開頭省略掉應用程式的包名,後面直接加上子類的類名(即“.MainActivity”)。
(2)android:process,該屬性值用於表示Activity組件應該運行在哪個進程中,一般情況下不用設定該屬性,所有的組件均運行在同一個進程中。如果該值以“:”開頭將會為該Activity建立一個私人的新進程;如果該值以小寫字母開頭將會建立一個全域的新進程。
(3)android:permission,該屬性值用於指定啟動該Activity所必須具有的許可權。
(4)android:screenOrientation,該屬性值用於設定螢幕方向,可以選擇的設定值有:unspecified(預設值,由系統來選擇方向)、landecape(橫向顯示,寬度比高度大)、portrait(縱向顯示,高度比寬度大)、user(使用使用者當前首選的方向)、behind(使用與Activity堆棧中該Activity之下的那個Activity相同的方向)、sensor(顯示的方向由裝置的方向感應器來決定)、nosensor(螢幕的顯示方向不會參照物理方向感應器)。
(5)android:launchMode,該屬性值用於設定Activity的啟動模式,可以選擇的設定值有:standard、singleTop、singleTask、singleInstance。
(6)android:theme,該屬性值用於設定Activity的主題模式。
1.2 <Activity>標籤的內嵌標籤
在<Activity></Activity>標籤中,可以內嵌以下兩個標籤:
(1)<intent-filter></intent-filter>,該標籤指明了Activity組件的過濾規則。
(2)<meda-data>,該標籤指明了額外的提供給Activity組件的資料值。
1.3不同包下的Activity註冊方法
當應用程式中包含多個Activity,並且這些Activity不在同一個包中時,註冊Activity時需要做一點小小的改動。
比如,在圖1所示的工程中包含了3個Activity,且這3個Activity處於不同的包中。
圖1 工程目錄結構
那麼,在註冊AddDialogActivity和DeleteDialogActivity時,使用上述代碼中和註冊MainActivity一樣的方法是行不通的。因為上述代碼指定了package="com.example.android_datastorage_sqlite",所以可以使用android:name=".MainActivity"的方式註冊MainActivity。但是很顯然,AddDialogActivity和DeleteDialogActivity並不在包"com.example.android_datastorage_sqlite"中,所以我們應當使用android:name=".userOerate.AddDialogActivity"和android:name=".userOerate.DeleteDialogActivity"的方式來註冊AddDialogActivity和DeleteDialogActivity組件。
2.Activity生命週期
Activity的生命週期包含3個階段,7個方法。具體可以參閱博文《Android學習筆記04:Activity及Activity生命週期》。這裡便不再贅述了。
3.Activity內容的兩種聲明方式
Activity顯示內容有兩種聲明方式,一種是通過xml布局檔案來聲明,一種是將螢幕設定為某個繼承自View類的對象。
3.1通過xml布局檔案聲明
Activity的xml布局檔案位於工程的res目錄下的layout目錄中,一個布局檔案就相當於一個View容器,其中可以添加Android系統內建的View(比如Button、TextView等),也可以添加自訂的繼承自View類的子類對象,甚至是View容器。
同時,在xml布局檔案還可以指定View對象在View容器中的相片順序(比如線性布局LinearLayout等)。
通過xml布局檔案將不同的View對象整合在一起確實非常方便,但是留給開發人員的自主性卻不夠。尤其是當進行遊戲編程時,往往Android系統中內建的View對象並不能完全滿足設計需求。在這種情況下,一般需要通過繼承和擴充View類來開發自己想要的使用者介面。
3.2通過View類的子類對象聲明
使用View類的子類對象作為Activity所要顯示的內容,可以通過以下的兩個步驟來實現:
(1)編寫一個繼承自View類的MyView類,在MyView類中需要實現onDraw(Canvas canvas)方法。在該方法中通過操作Canvas對象,完成介面的繪製工作。
(2)實現了介面的繪製之後,就可以在Activity中通過setContentView(View view)方法載入MyView對象,從而讓繪製的介面顯示出來。
以上兩個步驟的具體實現方法,可以參閱博文《Android學習筆記09:Paint及Canvas的簡單應用》。
4.Activity之間的通訊
Intent對象是組件之間通訊的載體,組件之間進行通訊就是一個個Intent對象在不斷的傳遞。Intent對象不僅可以運行在相同的組件之間(如Activity之間的通訊),也可以運行在不同的組件之間(如Activity與Service之間的通訊)。
對於Activity組件,Intent主要通過調用Context.startActivity()、Context.startActivityForResult()方法實現傳遞,其結果是啟動一個新的Activity或者使當前的Activity開始新的任務。
關於如何使用以上兩個方法實現Activity之間的通訊,可以參閱博文《Android學習筆記33:Intent介紹及Intent在Activity中的使用方法》。
5.儲存Activity臨時狀態資料
在Activity中提供了onSaveInstanceState()方法,用於當前Activity在系統未經你許可的情況下(比如處於暫停或停止狀態的Activity,在系統資源極度匱乏時,有可能被殺死)被銷毀時,對當前Activity中的臨時狀態資料進行儲存。
使用onSaveInstanceState(Bundle outState)方法,可以在Activity被殺掉之前將Activity的臨時狀態資料以索引值對的形式存放到Bundle對象中,從而能夠在再次調用OnCreate()方法時恢複Activity狀態。
如下的代碼使用onSaveInstanceState()方法對EditText對象中的輸入內容進行了儲存,並在OnCreate()方法中對EditText對象中的資料進行了恢複。
1 EditText mEditText; //EditText對象,用於輸入內容 2 private static final String KEY1 = "editTextValues"; //用於儲存EditText對象內容的鍵 3 private static final String TAG = "MainActivity"; //Log輸出過濾器 4 5 /* 6 * Function : onCreate方法,Activity建立時調用 7 * Author : 部落格園-依舊淡然 8 */ 9 public void onCreate(Bundle savedInstanceState) {10 super.onCreate(savedInstanceState);11 setContentView(R.layout.activity_main);12 mEditText = (EditText)this.findViewById(R.id.edittext);13 14 //如果Bundle對象中儲存有所需對象的內容,則恢複該對象內容15 if((savedInstanceState != null) && savedInstanceState.containsKey(KEY1)) {16 mEditText.setText(savedInstanceState.getString(KEY1));17 }18 Log.i(TAG, "-->onCreate()");19 }20 21 /*22 * Function : onSaveInstanceState方法,銷毀Activity時調用23 * Author : 部落格園-依舊淡然24 */25 protected void onSaveInstanceState(Bundle outState) {26 super.onSaveInstanceState(outState);27 String editTextValues = mEditText.getText().toString(); //擷取EditText對象內容28 outState.putString(KEY1, editTextValues); //以索引值對的形式儲存EditText對象內容29 Log.i(TAG, "-->onSaveInstanceState()");30 }
需要注意的一點是,onSaveInstanceState()方法並不是總會被調用的,只有系統為了節省記憶體資源而強制銷毀Activity時才會調用,所以應當僅僅通過重寫onSaveInstanceState()方法來儲存一些臨時資料,而不是持久資料。要儲存持久資料,應該使用onPause()方法。
6.Activity的主題模式
上面已經提到,通過設定<Activity></Activity>標籤下的android:theme屬性值,可以設定Activity的主題模式。
在Android系統中預設了以下一些主題模式:
(1)android:theme="@android:style/Theme.Dialog",將一個Activity顯示為對話方塊模式
(2)android:theme="@android:style/Theme.NoTitleBar",不顯示應用程式標題欄
(3)android:theme="@android:style/Theme.NoTitleBar.Fullscreen",不顯示應用程式標題欄,且全螢幕顯示該Activity
(4)android:theme="@android:style/Theme.Light",將Activity的背景設定為白色
(5)android:theme="@android:style/Theme.Light.NoTitleBar",將Activity的背景設定為白色,且不顯示應用程式標題欄
(6)android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen",將Activity的背景設定為白色,不顯示應用程式標題欄,且全螢幕顯示該Activity
(7)android:theme="@android:style/Theme.Black",將Activity的背景設定為黑色
(8)android:theme="@android:style/Theme.Black.NoTitleBar",將Activity的背景設定為黑色,且不顯示應用程式標題欄
(9)android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen",將Activity的背景設定為黑色,不顯示應用程式標題欄,且全螢幕顯示該Activity
(10)android:theme="@android:style/Theme.Wallpaper",以系統案頭做為Activity的背景
(11)android:theme="@android:style/Theme.Wallpaper.NoTitleBar",以系統案頭做為Activity的背景,且不顯示應用程式標題欄
(12)android:theme="@android:style/Theme.Wallpaper.NoTitleBar.Fullscreen",以系統案頭做為Activity的背景,不顯示應用程式標題欄,且全螢幕顯示該Activity
比如,我們可以通過設定android:theme="@android:style/Theme.Dialog",將一個Activity仿造成對話方塊Dialog的樣子,2所示。
圖2 對話方塊模式的Activity