Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android官方文檔之App Components(Activities)

Android官方文檔之App Components(Activities)

編輯:關於Android編程

Activity是Android四大組件之首,本文將介紹Activity的含義、創建、啟動、銷毀、生命周期 等。


如需訪問官方原文,您可以點擊這個鏈接:《Activities》


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(Creating an Activity)


為了創建一個Activity,必須繼承Activity類,並重寫生命周期方法。如onCreate(), onStop(), onResume(), onDestroy() 等。其中最重要的回調方法為:

onCreate():必須重寫該方法,系統會在創建Activity時回調。在該方法中,可以進行一些必要的組件初始化,另外,必須調用setContentView()方法綁定視圖。

onPause():當Activity由可見變成不可見狀態時,系統會回調該方法。在該方法中,應對用戶的改變操作做一些持久化保存。


更多有關Activity生命周期的官方原文,您可以點擊這個鏈接:《Managing the Activity Lifecycle》。


綁定UI(Implementing a user interface)


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》。


在manifest文件中注冊Activity(Declaring the activity in the manifest)


為了讓系統識別代碼中定義的Activity,您需要在manifest清單文件中注冊該Activity,格式如下:


  
      
      ...
  
  ...

在activity標簽中,只有android:name屬性是不可缺省的。使用theme、icon等屬性可以為Activity設置主題、圖標等。一旦確定了Activity的名字,就不可再修改,否則會破壞一些功能,有關這方面的內容,您可以參考這篇博客:《Things That Cannot Change》


在activity標簽中使用intent-filters(Using intent filters)


在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(Starting an Activity)


為了啟動一個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並返回結果(Starting an activity for a result)


為了得到啟動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...
        }
    }
}

終止activity(Shutting Down an Activity)


調用finish()方法可以手動終止activity,也可以調用finishActivity()方法手動終止之前啟動而不在前台的activity。


!請注意:大多數情況下,請不要手動終止activity,activity會根據其生命周期的狀態自動終止。手動終止activity會影響用戶體驗,除非一些極端情況,請不要手動終止activity。


管理Activity的生命周期(Managing the Activity Lifecycle)


通過回調的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時,該實例必須重新創建。


重寫生命周期回調方法(Implementing the lifecycle callbacks)


當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? 接下來回調的方法 onCreate() 當activity第一次啟動時回調,可為activity做靜態初始化,如初始化View、為ListView綁定數據等;該方法回傳一個Bundle 參數,該參數保存了上次在activity中存儲的信息。 否 onStart() onRestart() activity處於stop狀態而准備從新啟動時 否 onStart() onStart() 當activity處於可見狀態時,activity實例剛被壓入後退棧 否 onResume() 或 onStop() onResume() 在用戶處於可交互狀態之前回調 否 onPause() onPause() 在其他activity准備啟動之前調用,一般會在該方法中對一些數據進行持久化保存,停止動畫等。在該方法中執行的操作不能過於繁瑣,否則將影響新的activity的創建。 是 onResume() 或 onStop() onStop() UI界面不再可見時回調 是 onRestart() 或 onDestroy() onDestroy() activity示例銷毀時調用。可能是開發者主動調用了finish()方法到時onDestroy()回調,也可能是系統的內存緊張而回調,您可以調用isFinishing()方法判斷是上述那種情況到時onDestroy()被回調。 是 無

在“系統是否可以在該方法執行後殺死activity?”這一列中,有三個方法的結果為“是”(onPause(), onStop(), 和 onDestroy())。當內容及其緊張時,onPause()方法將被回調,而onStop() 和 onDestroy()方法不被回調,所以在onPause()方法中應對一些關鍵的、輕量的數據做持久化保存;在其他為“否”的回調方法中,也並不是說activity不能在這期間被殺死,只是這種情況基本不存在(內存中無可用空間)。


保存activity狀態(Saving activity state)


當系統回調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銷毀並重建的過程,這是一個很好的測試。


處理配置改變所帶來的問題(Handling configuration changes)


設備的配置可能在運行時發生改變(如旋轉屏幕,鍵盤可見於不可見,語言環境發生改變等),此時onDestroy()方法會被回調,並接著立刻回調onCreate()方法,這時之前在界面上保存的信息可能會消失。
最好的解決方式就是回調onSaveInstanceState() 和 onRestoreInstanceState()方法(或onCreate())。更多有關配置改變的內容,您可以參考這個官方文檔《Handling Runtime Changes》


協調啟動activity(Coordinating activities)


當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()方法中。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved