編輯:關於Android編程
Activity是Android四大組件之首,本文將介紹Activity的含義、創建、啟動、銷毀、生命周期 等。
如需訪問官方原文,您可以點擊這個鏈接:《Activities》
Activity是一個類,它是Android呈現界面的載體,用於與用戶操作交互,如撥號、照相、發送郵件、展示地圖 等。每個Activity都承載了一個Window,這個Window用來繪制UI(User Interface)。一般情況下,該Window鋪滿(fill)整個屏幕;有時候,它也可以懸浮於其它Window之上(float on top of other windows)。
通常,一個Android應用程序可包含多個activity,每個activity之間耦合較松(loosely bound to each other)。一般都有一個主activity,用於在啟動程序時啟動,每個activity都可以啟動其他activity,每當一個新的activity被啟動時,原來的activity就會處於stop狀態,並把該activity實例保存在後退棧中(back stack),新啟動的activity會被裝入後退棧中並獲得焦點。後退棧的存儲機制是後進先出(last in, first out),所以當用戶點擊返回鍵時,頂端的activity將從棧頂彈出,並被destroyed,處於stop狀態的activity進入resume狀態。有關任務棧和返回棧的官方文檔,您可以參考官方文檔:《Tasks and Back Stack》,我將在後續翻譯該文檔。
當一個新的activity啟動時,原來的activity將處於stop狀態,在這個過程中,activity將回調其相應的生命周期方法來改變狀態,activity有若干個生命周期回調方法,在每個方法中,可以做一些相應的工作,比如當activity進入stop狀態時,系統會回調onStop()方法,在這個方法中,可以釋放一些大的對象(release any large objects),如網絡或數據庫連接,當activity進入resume狀態時,系統會回調onResume()方法,在這個方法中,可以重新獲得一些重要的資源(eacquire the necessary resources)、重新開始一些被終止的action(resume actions that were interrupted)等。
為了創建一個Activity,必須繼承Activity類,並重寫生命周期方法。如onCreate(), onStop(), onResume(), onDestroy() 等。其中最重要的回調方法為:
onCreate():必須重寫該方法,系統會在創建Activity時回調。在該方法中,可以進行一些必要的組件初始化,另外,必須調用setContentView()
方法綁定視圖。
onPause():當Activity由可見變成不可見狀態時,系統會回調該方法。在該方法中,應對用戶的改變操作做一些持久化保存。
更多有關Activity生命周期的官方原文,您可以點擊這個鏈接:《Managing the Activity Lifecycle》。
Activity承載的UI由一系列嵌套的View組成(a hierarchy of views),這些View都是繼承於View類,每個View都控制著一個長方形的區域,並與用戶交互。
Android內置了大量的View,您可以定制View的布局,如button, text field, checkbox, 或僅僅是一張image。ViewGroup類也繼承於View類,它負責View的布局(layout),linear layout, a grid layout, relative layout都是不同的布局方式。您也可以繼承View或ViewGroup來定制自己的布局。
最普遍的定義布局方式是在資源文件夾中創建XML布局文件。通過這種方式,您可以降低布局與Activity實現邏輯之間的耦合,您可以通過setContentView()
方法將一個Activity與一個layout布局綁定。
更多有關布局的內容,您可以參考官方文檔《User Interface》。
為了讓系統識別代碼中定義的Activity,您需要在manifest清單文件中注冊該Activity,格式如下:
...
...
在activity標簽中,只有android:name
屬性是不可缺省的。使用theme、icon等屬性可以為Activity設置主題、圖標等。一旦確定了Activity的名字,就不可再修改,否則會破壞一些功能,有關這方面的內容,您可以參考這篇博客:《Things That Cannot Change》
在activity標簽中,可以指定多個
標簽,該標簽用於定義本activity具有何種性質以及其他應用程序如何啟動本activity。
如需將一個activity定義為一個應用程序的主入口,可按如下方式定義:
若您希望activity只能由自己的應用程序啟動(not allow other applications to activate its activities),那麼不要為這個activity設置intent-filter。一個應用程序中只允許一個activity的intent-filter是 “main” action 和”launcher” category。Android不鼓勵使用顯式intent啟動跨應用activity。
更多有關intent-filter的內容,您可以參考官方文檔:《Intents and Intent Filters》,或者我翻譯的博文:《Android官方文檔之App Components(Intents and Intent Filters)》。
為了啟動一個activity,您可以調用startActivity()
方法並傳入Intent對象參數。Intent對象可以包含了action參數,action用於指定目標activity具備的性質,另外,Intent還能攜帶少量數據。
若啟動同一應用程序的activity,可以使用顯示Intent,如:
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
更多的時候,是通過隱式Intent來啟動activity,如啟動一個發送郵件的activity:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
系統提供了大量的內置action,以便隱式啟動系統自帶的應用程序的activity,有關這部分的內容,您可以參考官方原文:《Common Intents》或我的翻譯的博文:《Android官方文檔之App Components(Common Intents)》。
為了得到啟動activity的返回結果,您可以調用startActivityForResult()方法代替startActivity()方法,並在onActivityResult()回調方法中接收結果(從該方法的Intent參數中獲取)。
下面舉一個獲取通訊錄聯系人的例子:
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...
}
}
}
調用finish()方法可以手動終止activity,也可以調用finishActivity()方法手動終止之前啟動而不在前台的activity。
!請注意:大多數情況下,請不要手動終止activity,activity會根據其生命周期的狀態自動終止。手動終止activity會影響用戶體驗,除非一些極端情況,請不要手動終止activity。
通過回調的Activity生命周期方法,可以管理Activity的生命周期。Activity會至少處於這三個狀態:
Resumed(或running):這時Activity處於前台並獲得焦點。
Paused:當另一個Activity處於前台並獲得焦點時,原Activity失去焦點但仍有部分可見,此時原Activity處於pause狀態。處於pause狀態的Activity在內存中仍有其實例,且依附於window manager,它擁有暫停之前的所有狀態,但系統可以在內存及其少的時候銷毀它(can be killed by the system in extremely low memory situations)。
Stopped:當另一個Activity將原Activity完全遮擋時(completely obscured by another activity ),原Activity處於stopped狀態。處於stopped狀態的Activity在內存中仍有其實例,但不再依附於window manager,系統可以在需要內存的時候銷毀它(can be killed by the system when memory is needed elsewhere)。
當Activity處於pause或stopped狀態時,系統可以在其內存緊張時調用finish()方法銷毀該Activity實例、或僅僅是殺死應用所在進程(simply killing its process)。當需要再次啟動該Activity時,該實例必須重新創建。
當Activity在上述不同狀態之間切換時,系統會回調Activity中的相應方法,如下所示:
public class ExampleActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// The activity is being created.
}
@Override
protected void onStart() {
super.onStart();
// The activity is about to become visible.
}
@Override
protected void onResume() {
super.onResume();
// The activity has become visible (it is now "resumed").
}
@Override
protected void onPause() {
super.onPause();
// Another activity is taking focus (this activity is about to be "paused").
}
@Override
protected void onStop() {
super.onStop();
// The activity is no longer visible (it is now "stopped")
}
@Override
protected void onDestroy() {
super.onDestroy();
// The activity is about to be destroyed.
}
}
!請注意:在重寫這些回調方法之前,請務必先調用它們的父類方法。就像示例中的那樣。
在這些回調方法中,包含了三個嵌套的內循環生命周期(three nested loops ):
完整生命周期(entire lifetime):從onCreate()到onDestroy()。應在兩個方法中處理一些全局的內容,如在onCreate()中初始化layout資源,並在onDestroy()方法中釋放。如果在Activity中需要開啟一個線程,訪問網絡下載文件,那麼應在onCreate()中創建線程並在onDestroy()中停止線程。
可見生命周期(visible lifetime):從onStart()到onStop(),在這個生命周期中,用戶能看到該Activity承載的UI界面並與之交互(the user can see the activity on-screen and interact with it),如當onStop()方法被回調時,該Activity將不再可見,而新的Activity正處於啟動狀態。在這兩個方法之間,您可以向用戶展示一些資源,如您可以在onStart()方法中注冊BroadcastReceiver,並在onStop()方法中解除注冊。
前台生命周期(foreground lifetime):從onResume()到onPause(),在這期間,Activity處於所有其他Activity的最上層並獲得用戶輸入焦點,系統可以在前台生命周期中快速切換,如當設備休眠或者對話框彈出時,onPause()被回調。正因為可以快速切換,所以在這兩個方法中盡量不要做較重的工作。下圖展示Activity生命周期的整個過程:
下表對activity生命周期做一總結:
在“系統是否可以在該方法執行後殺死activity?”這一列中,有三個方法的結果為“是”(onPause(), onStop(), 和 onDestroy())。當內容及其緊張時,onPause()方法將被回調,而onStop() 和 onDestroy()方法不被回調,所以在onPause()方法中應對一些關鍵的、輕量的數據做持久化保存;在其他為“否”的回調方法中,也並不是說activity不能在這期間被殺死,只是這種情況基本不存在(內存中無可用空間)。
當系統回調onPause()或onStop()方法時,activity實例在內存中仍然可見,所以當activity重新可見時,activity中的數據仍會原封不動地顯示出來。
然而,有些時候activity實例會因為系統的內存不足而被回收,當activity再被重新創建時,系統將無法保證之前在界面中輸入的數據可被完整地恢復,這時需要重寫onSaveInstanceState()方法對數據做保存。
onSaveInstanceState()方法一般在activity實例即將被系統回收時(the activity vulnerable to destruction)回調,您可以在該方法回傳的Bundle參數中保存鍵值對格式的數據,接著當activity因為內存緊張、屏幕轉屏等原因被銷毀時,該Bundle參數會同時傳遞至onCreate() 和 onRestoreInstanceState()方法中,當再次啟動該activity時,回調onCreate() 或 onRestoreInstanceState(),可以從Bundle參數從獲取之前保存的數據。若Bundle中沒有數據,將為null。
onCreate() 和 onRestoreInstanceState()的區別在於:前者在每次初始化activity時必被回調,所以回傳的Bundle參數可能為null,這需要在獲取Bundle參數前做一判斷;而後者只有在向Bundle中保存了數據後才會回調,所以不需要對Bundle判斷是否為空,直接獲取Bundle就可以。
activity的數據保存如下所示:
onSaveInstanceState()方法並非一定在destroy之前調用,當用戶點擊後退鍵主動退出activity時,onSaveInstanceState()可能在onStop()甚至是onPause()之前就被回調。
即便您不主動復寫onSaveInstanceState()方法,系統也會回調該方法,並保存一些與View對應的layout布局信息(如CheckBox是否勾選、EditText中鍵入的內容等),當設備由豎屏切換至橫屏時,橫屏的Layout會被加載,並恢復onSaveInstanceState()中保存的布局信息,而整個的保存過程是通過同一View的不同布局的同一ID而恢復的,也就是說,若需要保存某個控件的鍵入信息,只需要在為其設置不同布局時(如橫豎屏對應兩個布局)為該控件指定同一ID即可。
當然,您也可以在activity標簽中將android:saveEnabled屬性設為false、或調用setSaveEnabled(false),來阻止onSaveInstanceState()方法自動保存layout信息,但一般不推薦這麼做。
在實際開發中,推薦重寫onSaveInstanceState()方法以保存額外的重要的信息,並在保存信息之前先調用父類的onSaveInstanceState()方法,這樣可以保證layout布局、控件等信息被保存。
!請注意:由於onSaveInstanceState()方法不保證一定會被回調,所以一般使用onSaveInstanceState()方法保存一些UI界面上的即時信息,而不應用它保存持久化的內容;而應在onPause()方法中保存需要持久化的數據(如將數據存入Database中)
您可以通過旋轉屏幕來測試信息是否已經有效保存,因為屏幕的旋轉在設備使用過程中經常發生,若不能很好的保存數據,將破壞用戶體驗;另外,屏幕旋轉就是一個activity銷毀並重建的過程,這是一個很好的測試。
設備的配置可能在運行時發生改變(如旋轉屏幕,鍵盤可見於不可見,語言環境發生改變等),此時onDestroy()方法會被回調,並接著立刻回調onCreate()方法,這時之前在界面上保存的信息可能會消失。
最好的解決方式就是回調onSaveInstanceState() 和 onRestoreInstanceState()方法(或onCreate())。更多有關配置改變的內容,您可以參考這個官方文檔《Handling Runtime Changes》
當Activity A 啟動Activity B 時,下列回調將會發生:
Activity A回調onPause(); Activity B依次回調onCreate(), onStart(), 和 onResume();(此時Activity B 處於前台) Activity A 回調onStop();(Activity A不再可見)上述步驟的一個應用場景是:若您希望將Activity A中的數據保存至Database中,並在Activity B中獲取時,應在Activity A中的onPause()方法中保存,而不是在onStop()方法中。
一、著色游戲概述近期群裡偶然看到一哥們在群裡聊不規則圖像填充什麼四聯通、八聯通什麼的,就本身好學務實的態度去查閱了相關資料。對於這類著色的資料,最好的就是去搜索些相關ap
demo效果增加數據: 刪除數據 修改數據 SQLite介紹SQLite,是一款輕型的數據庫,是遵守ACID的關系型數據庫管理系統,它包含在一個相對
本文實例講述了Android編程之SMS讀取短信並保存到SQLite的方法。分享給大家供大家參考,具體如下:Android 之 SMS 短信在Android系統中是保存在
今天隨便逛逛CSDN,看到主頁上推薦了一篇文章Android 快速開發系列 打造萬能的ListView GridView 適配器,剛好這兩天寫項目自己也封裝了類似的Com