Android官方文檔之App Components(Activities)

來源:互聯網
上載者:User

標籤:

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,格式如下:

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

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

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

在activity標籤中,可以指定多個<intent-filter>標籤,該標籤用於定義本activity具有何種性質以及其他應用程式如何啟動本activity。

如需將一個activity定義為一個應用程式的主入口,可按如下方式定義:

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

若您希望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);}@Overrideprotected 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 時,下列回調將會發生:

  1. Activity A回調onPause();
  2. Activity B依次回調onCreate(), onStart(), 和 onResume();(此時Activity B 處於前台)
  3. Activity A 回調onStop();(Activity A不再可見)

上述步驟的一個應用情境是:若您希望將Activity A中的資料儲存至Database中,並在Activity B中擷取時,應在Activity A中的onPause()方法中儲存,而不是在onStop()方法中。

Android官方文檔之App Components(Activities)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.