Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android開發應用中Activity詳解

Android開發應用中Activity詳解

編輯:Android開發實例

  Android應用開發中會經常遇到Activity組件的使用,下面就來講解下Activity組件。Activity的生命周期、通信方式和IntentFilter等內容,並提供了一些日常開發中經常用到的關於Activity的技巧和方法。通過本文,你可以進一步了接Android中Activity的運作方式。

  Activity的生命周期

  和J2ME的MIDlet一樣,在android中,Activity的生命周期交給系統統一管理。與MIDlet不同的是安裝在android中的所有的Activity都是平等的。

  Activity的狀態及狀態間的轉換

  在android中,Activity擁有四種基本狀態:

  Active/Runing一個新Activity啟動入棧後,它在屏幕最前端,處於棧的最頂端,此時它處於可見並可和用戶交互的激活狀態。

  Paused當Activity被另一個透明或者Dialog樣式的Activity覆蓋時的狀態。此時它依然與窗口管理器保持連接,系統繼續維護其內部狀態,所以它仍然可見,但它已經失去了焦點故不可與用戶交互。

  Stoped當Activity被另外一個Activity覆蓋、失去焦點並不可見時處於Stoped狀態。

  KilledActivity被系統殺死回收或者沒有被啟動時處於Killed狀態。

  當一個Activity實例被創建、銷毀或者啟動另外一個Activity時,它在這四種狀態之間進行轉換,這種轉換的發生依賴於用戶程序的動作。下圖說明了Activity在不同狀態間轉換的時機和條件:

  圖1.Activity的狀態轉換







  如上所示,Android程序員可以決定一個Activity的“生”,但不能決定它的“死”,也就時說程序員可以啟動一個Activity,但是卻不能手動的“結束”一個Activity。當你調用Activity.finish()方法時,結果和用戶按下BACK鍵一樣:告訴ActivityManager該Activity實例完成了相應的工作,可以被“回收”。隨後ActivityManager激活處於棧第二層的Activity並重新入棧,同時原Activity被壓入到棧的第二層,從Active狀態轉到Paused狀態。例如:從Activity1中啟動了Activity2,則當前處於棧頂端的是Activity2,第二層是Activity1,當我們調用Activity2.finish()方法時,ActivityManager重新激活Activity1並入棧,Activity2從Active狀態轉換Stoped狀態,Activity1.onActivityResult(intrequestCode,intresultCode,Intentdata)方法被執行,Activity2返回的數據通過data參數返回給Activity1。

  Activity棧

  Android是通過一種Activity棧的方式來管理Activity的,一個Activity的實例的狀態決定它在棧中的位置。處於前台的Activity總是在棧的頂端,當前台的Activity因為異常或其它原因被銷毀時,處於棧第二層的Activity將被激活,上浮到棧頂。當新的Activity啟動入棧時,原Activity會被壓入到棧的第二層。一個Activity在棧中的位置變化反映了它在不同狀態間的轉換。Activity的狀態與它在棧中的位置關系如下圖所示:

  圖2.Activity的狀態與它在棧中的位置關系

  如上所示,除了最頂層即處在Active狀態的Activity外,其它的Activity都有可能在系統內存不足時被回收,一個Activity的實例越是處在棧的底層,它被系統回收的可能性越大。系統負責管理棧中Activity的實例,它根據Activity所處的狀態來改變其在棧中的位置。

  Activity生命周期

  在android.app.Activity類中,Android定義了一系列與生命周期相關的方法,在我們自己的Activity中,只是根據需要復寫需要的方法,Java的多態性會保證我們自己的方法被虛擬機調用,這一點與J2ME中的MIDlet類似。

  publicclassOurActivityextendsActivity{

  protectedvoidonCreate(BundlesavedInstanceState);

  protectedvoidonStart();

  protectedvoidonResume();

  protectedvoidonPause();

  protectedvoidonStop();

  protectedvoidonDestroy();

  }

  這些方法的說明如下:

  protectedvoidonCreate(BundlesavedInstanceState)一個Activity的實例被啟動時調用的第一個方法。一般情況下,我們都覆蓋該方法作為應用程序的一個入口點,在這裡做一些初始化數據、設置用戶界面等工作。大多數情況下,我們都要在這裡從xml中加載設計好的用戶界面。例如:

  setContentView(R.layout.main);

  當然,也可從savedInstanceState中讀我們保存到存儲設備中的數據,但是需要判斷savedInstanceState是否為null,因為Activity第一次啟動時並沒有數據被存貯在設備中:

  if(savedInstanceState!=null){

  savedInstanceState.get("Key");

  }

  protectedvoidonStart()該方法在onCreate()方法之後被調用,或者在Activity從Stop狀態轉換為Active狀態時被調用。

  protectedvoidonResume()在Activity從Pause狀態轉換到Active狀態時被調用。

  protectedvoidonResume()在Activity從Active狀態轉換到Pause狀態時被調用。

  protectedvoidonStop()在Activity從Active狀態轉換到Stop狀態時被調用。一般我們在這裡保存Activity的狀態信息。

  protectedvoidonDestroy()在Active被結束時調用,它是被結束時調用的最後一個方法,在這裡一般做些釋放資源,清理內存等工作。

  圖3.這些方法的調用時機

  此外,Android還定義了一些不常用的與生命周期相關的方法可用:

  protectedvoidonPostCreate(BundlesavedInstanceState);

  protectedvoidonRestart();

  protectedvoidonPostResume();

  Android提供的文檔詳細的說明了它們的調用規則。

  創建一個Activity

  在android中創建一個Activity是很簡單的事情,編寫一個繼承自android.app.Activity的Java類並在AndroidManifest.xml聲明即可。下面是一個為了研究Activity生命周期的一個Activity實例(工程源碼見下載):

  Activity文件:

  publicclassEX01extendsActivity{

  privatestaticfinalStringLOG_TAG=EX01.class.getSimpleName();

  @Override

  publicvoidonCreate(BundlesavedInstanceState){

  super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

  Log.e(LOG_TAG,"onCreate");

  }

  @Override

  protectedvoidonStart(){

  Log.e(LOG_TAG,"onStart");

  super.onStart();

  }

  @Override

  protectedvoidonResume(){

  Log.e(LOG_TAG,"onResume");

  super.onResume();

  }

  @Override

  protectedvoidonPause(){

  Log.e(LOG_TAG,"onPause");

  super.onPause();

  }

  @Override

  protectedvoidonStop(){

  Log.e(LOG_TAG,"onStop");

  super.onStop();

  }

  @Override

  protectedvoidonDestroy(){

  Log.e(LOG_TAG,"onDestroy");

  super.onDestroy();

  }

  }

  AndroidManifest.xml中通過<activity>節點說明Activity,將apk文件安裝後,系統根據這裡的說明來查找讀取Activity,本例中的說明如下:

  <activityandroid:name=".EX01"android:label="@string/app_name">

  <intent-filter>

  <actionandroid:name="android.intent.action.MAIN"/>

  <categoryandroid:name="android.intent.category.LAUNCHER"/>

  </intent-filter>

  </activity>

  啟動另外一個Activity

  Activity.startActivity()方法可以根據傳入的參數啟動另外一個Activity:

  Intentintent=newIntent(CurrentActivity.this,OtherActivity.class);

  startActivity(intent);

  當然,OtherActivity同樣需要在AndroidManifest.xml中定義。

  Activity之間通信

  使用Intent通信

  在Android中,不同的Activity實例可能運行在一個進程中,也可能運行在不同的進程中。因此我們需要一種特別的機制幫助我們在Activity之間傳遞消息。Android中通過Intent對象來表示一條消息,一個Intent對象不僅包含有這個消息的目的地,還可以包含消息的內容,這好比一封Email,其中不僅應該包含收件地址,還可以包含具體的內容。對於一個Intent對象,消息“目的地”是必須的,而內容則是可選項。

  在上面的實例中通過Activity.startActivity(intent)啟動另外一個Activity的時候,我們在Intent類的構造器中指定了“收件人地址”。

  如果我們想要給“收件人”Activity說點什麼的話,那麼可以通過下面這封“e-mail”來將我們消息傳遞出去:

  Intentintent=newIntent(CurrentActivity.this,OtherActivity.class);

  //創建一個帶“收件人地址”的email

  Bundlebundle=newBundle();//創建email內容

  bundle.putBoolean("boolean_key",true);//編寫內容

  bundle.putString("string_key","string_value");

  intent.putExtra("key",bundle);//封裝email

  startActivity(intent);//啟動新的Activity

  那麼“收件人”該如何收信呢?在OtherActivity類的onCreate()或者其它任何地方使用下面的代碼就可以打開這封“e-mail”閱讀其中的信息:

  Intentintent=getIntent();//收取email

  Bundlebundle=intent.getBundleExtra("key");//打開email

  bundle.getBoolean("boolean_key");//讀取內容

  bundle.getString("string_key");

  上面我們通過bundle對象來傳遞信息,bundle維護了一個HashMap<String,Object>對象,將我們的數據存貯在這個HashMap中來進行傳遞。但是像上面這樣的代碼稍顯復雜,因為Intent內部為我們准備好了一個bundle,所以我們也可以使用這種更為簡便的方法:

  Intentintent=newIntent(EX06.this,OtherActivity.class);

  intent.putExtra("boolean_key",true);

  intent.putExtra("string_key","string_value");

  startActivity(intent);

  接收:

  Intentintent=getIntent();

  intent.getBooleanExtra("boolean_key",false);

  intent.getStringExtra("string_key");

  使用SharedPreferences

  SharedPreferences使用xml格式為Android應用提供一種永久的數據存貯方式。對於一個Android應用,它存貯在文件系統的/data/data/your_app_package_name/shared_prefs/目錄下,可以被處在同一個應用中的所有Activity訪問。Android提供了相關的API來處理這些數據而不需要程序員直接操作這些文件或者考慮數據同步問題。

  //寫入SharedPreferences

  SharedPreferencespreferences=getSharedPreferences("name",MODE_PRIVATE);

  Editoreditor=preferences.edit();

  editor.putBoolean("boolean_key",true);

  editor.putString("string_key","string_value");

  editor.commit();

  //讀取SharedPreferences

  SharedPreferencespreferences=getSharedPreferences("name",MODE_PRIVATE);

  preferences.getBoolean("boolean_key",false);

  preferences.getString("string_key","default_value");

  其它方式

  Android提供了包括SharedPreferences在內的很多種數據存貯方式,比如SQLite,文件等,程序員可以通過這些API實現Activity之間的數據交換。如果必要,我們還可以使用IPC方式。

  Activity的IntentFilter

  IntentFilter描述了一個組件願意接收什麼樣的Intent對象,Android將其抽象為android.content.IntentFilter類。在Android的AndroidManifest.xml配置文件中可以通過<intent-filter>節點為一個Activity指定其IntentFilter,以便告訴系統該Activity可以響應什麼類型的Intent。

  當程序員使用startActivity(intent)來啟動另外一個Activity時,如果直接指定intent了對象的Component屬性,那麼ActivityManager將試圖啟動其Component屬性指定的Activity。否則Android將通過Intent的其它屬性從安裝在系統中的所有Activity中查找與之最匹配的一個啟動,如果沒有找到合適的Activity,應用程序會得到一個系統拋出的異常。這個匹配的過程如下:

  圖4.Activity種IntentFilter的匹配過程

  Action匹配

  Action是一個用戶定義的字符串,用於描述一個Android應用程序組件,一個IntentFilter可以包含多個Action。在AndroidManifest.xml的Activity定義時可以在其<intent-filter>節點指定一個Action列表用於標示Activity所能接受的“動作”,例如:

  <intent-filter>

  <actionandroid:name="android.intent.action.MAIN"/>

  <actionandroid:name="com.zy.myaction"/>

  ……

  </intent-filter>

  如果我們在啟動一個Activity時使用這樣的Intent對象:

  Intentintent=newIntent();

  intent.setAction("com.zy.myaction");

  那麼所有的Action列表中包含了“com.zy.myaction”的Activity都將會匹配成功。

  Android預定義了一系列的Action分別表示特定的系統動作。這些Action通過常量的方式定義在android.content.Intent中,以“ACTION_”開頭。我們可以在Android提供的文檔中找到它們的詳細說明。

  URI數據匹配

  一個Intent可以通過URI攜帶外部數據給目標組件。在<intent-filter>節點中,通過<data/>節點匹配外部數據。

  mimeType屬性指定攜帶外部數據的數據類型,scheme指定協議,host、port、path指定數據的位置、端口、和路徑。如下:

  <dataandroid:mimeType="mimeType"android:scheme="scheme"

  android:host="host"android:port="port"android:path="path"/>

  如果在IntentFilter中指定了這些屬性,那麼只有所有的屬性都匹配成功時URI數據匹配才會成功。

  Category類別匹配

  <intent-filter>節點中可以為組件定義一個Category類別列表,當Intent中包含這個列表的所有項目時Category類別匹配才會成功。

  一些關於Activity的技巧

  鎖定Activity運行時的屏幕方向

  Android內置了方向感應器的支持。在G1中,Android會根據G1所處的方向自動在豎屏和橫屏間切換。但是有時我們的應用程序僅能在橫屏/豎屏時運行,比如某些游戲,此時我們需要鎖定該Activity運行時的屏幕方向,<activity>節點的android:screenOrientation屬性可以完成該項任務,示例代碼如下:

  <activityandroid:name=".EX01"

  android:label="@string/app_name"

  android:screenOrientation="portrait">//豎屏,值為landscape時為橫屏

  …………

  </activity>

  全屏的Activity

  要使一個Activity全屏運行,可以在其onCreate()方法中添加如下代碼實現:

  //設置全屏模式

  getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

  WindowManager.LayoutParams.FLAG_FULLSCREEN);

  //去除標題欄

  requestWindowFeature(Window.FEATURE_NO_TITLE);

  在Activity的Title中加入進度條

  為了更友好的用戶體驗,在處理一些需要花費較長時間的任務時可以使用一個進度條來提示用戶“不要著急,我們正在努力的完成你交給的任務”。如下圖:

  在Activity的標題欄中顯示進度條不失為一個好辦法,下面是實現代碼:

  //不明確進度條

  requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

  setContentView(R.layout.main);

  setProgressBarIndeterminateVisibility(true);

  //明確進度條

  requestWindowFeature(Window.FEATURE_PROGRESS);

  setContentView(R.layout.main);

  setProgress(5000);

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