activity類處于android.app包中,繼承關系:
extends ContextThemeWrapper
implements LayoutInflater.Factory2 Window.Callback KeyEvent.CallbackView.OnCreateContextMenuListenerComponentCallbacks2
java.lang.Object?android.content.Context?android.content.ContextWrapper?android.view.ContextThemeWrapper?android.app.ActivityActivity 簡介
Activity是什么呢?Activity是一個應用程序提供與用戶進行交流的界面,
Android Activity 詳述
。每個Activity都可以通過布局來呈現自己的用戶界面,一個應用程序通常包括很多Activity,其中有一個被稱為主Activity,這是程序第一次啟動所展示的,例如很多程序都有的歡迎界面。將Activity設置成主Activity可以通過配置AndroidManifest.xml文件,將如下代碼復制到activity的標簽之中:<intent-filter><category android:name="android.intent.category.LAUNCHER"></category></intent-filter>
一個Activity可以啟動另一個Activity來實現不同的表現,當一個Activity啟動后,它被壓入一個stack中,獲得焦點,當用戶按了back按鈕后,當前的Activity從stack中彈出(即被destroyed),先前的Activity被釋放從新獲得焦點。這些涉及到Activity的生命周期,后面將進行討論。
怎么創(chuàng)建一個Activity呢?通過繼承父類Activity,來創(chuàng)建一個屬于自己的Activity,這要求你需要實現Activity父類的回調方法,這些方法在Activity的生命周期中的不同狀態(tài)被調用,如:創(chuàng)建,暫停,釋放,銷毀。其中有兩個最重要的回調方法:
1.onCreate()
這個方法在Activity被創(chuàng)建時被調用,在這個方法應該初始化各個控件,通過調用setContentView(R.layout.xxx)方法定義布局來展現Activity的用戶界面,其中R.layout.xxx為Activity的XML布局文件。
2.onPause()
這個方法在用戶離開當前Activity時被調用,這就需要在這個方法中保存用戶與當前Activity的會話,比如在EditText中輸入的值。用戶在返回當前Activity時,還應該顯示離開時所填寫的值。
當然每創(chuàng)建一個Activity都需要在AndroidManifest.xml文件中注冊一個相應的Activity。如:創(chuàng)建的Activity的類名為:MyActivity則在文件中需添加如下代碼:
Activity 的狀態(tài)及狀態(tài)間的轉換:
在 android 中,Activity 擁有四種基本狀態(tài):
Active/Runing一個新 Activity 啟動入棧后,它在屏幕最前端,處于棧的最頂端,此時它處于可見并可和用戶交互的激活狀態(tài)。Paused當 Activity 被另一個透明或者 Dialog 樣式的 Activity 覆蓋時的狀態(tài)。此時它依然與窗口管理器保持連接,系統(tǒng)繼續(xù)維護其內部狀態(tài),所以它仍然可見,但它已經失去了焦點故不可與用戶交互。Stoped當 Activity 被另外一個 Activity 覆蓋、失去焦點并不可見時處于Stoped狀態(tài)。KilledActivity 被系統(tǒng)殺死回收或者沒有被啟動時處于Killed狀態(tài)。
當一個 Activity 實例被創(chuàng)建、銷毀或者啟動另外一個 Activity 時,它在這四種狀態(tài)之間進行轉換,這種轉換的發(fā)生依賴于用戶程序的動作。下圖說明了 Activity 在不同狀態(tài)間轉換的時機和條件:
圖 1. Activity 的狀態(tài)轉換
如上所示,Android 程序員可以決定一個 Activity 的“生”,但不能決定它的“死”,也就時說程序員可以啟動一個 Activity,但是卻不能手動的“結束”一個 Activity。當你調用Activity.finish()方法時,結果和用戶按下 BACK 鍵一樣:告訴 Activity Manager 該 Activity 實例完成了相應的工作,可以被“回收”。隨后 Activity Manager 激活處于棧第二層的 Activity 并重新入棧,同時原 Activity 被壓入到棧的第二層,從 Active 狀態(tài)轉到 Paused 狀態(tài)。例如:從 Activity1 中啟動了 Activity2,則當前處于棧頂端的是 Activity2,第二層是 Activity1,當我們調用Activity2.finish()方法時,Activity Manager 重新激活 Activity1 并入棧,Activity2 從 Active 狀態(tài)轉換 Stoped 狀態(tài),Activity1. onActivityResult(int requestCode, int resultCode, Intent data)方法被執(zhí)行,Activity2 返回的數據通過data參數返回給 Activity1。
Activity 棧
Android 是通過一種 Activity 棧的方式來管理 Activity 的,一個 Activity 的實例的狀態(tài)決定它在棧中的位置。處于前臺的 Activity 總是在棧的頂端,當前臺的 Activity 因為異;蚱渌虮讳N毀時,處于棧第二層的 Activity 將被激活,上浮到棧頂。當新的 Activity 啟動入棧時,原 Activity 會被壓入到棧的第二層。一個 Activity 在棧中的位置變化反映了它在不同狀態(tài)間的轉換。Activity 的狀態(tài)與它在棧中的位置關系如下圖所示:
圖 2. Activity 的狀態(tài)與它在棧中的位置關系
如上所示,除了最頂層即處在 Active 狀態(tài)的 Activity 外,其它的 Activity 都有可能在系統(tǒng)內存不足時被回收,一個 Activity 的實例越是處在棧的底層,它被系統(tǒng)回收的可能性越大。系統(tǒng)負責管理棧中 Activity 的實例,它根據 Activity 所處的狀態(tài)來改變其在棧中的位置。
Activity 生命周期
在android.app.Activity類中,Android 定義了一系列與生命周期相關的方法,在我們自己的 Activity 中,只是根據需要復寫需要的方法.Activity生命周期圖:
下面我們通過一個實例來說明Activity生命周期。新建工程,編寫如下代碼:
public class MainActivity extends AppCompatActivity { private String TAG = MainActivity; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i(TAG, onCreate); } @Override protected void onResume() { super.onResume(); Log.i(TAG, onResume); } @Override protected void onStart() { super.onStart(); Log.i(TAG, onStart); } @Override protected void onPause() { super.onPause(); Log.i(TAG, onPause); } @Override protected void onStop() { super.onStop(); Log.i(TAG, onStop); } @Override protected void onRestart() { super.onRestart(); Log.i(TAG, onRestart); } @Override protected void onDestroy() { super.onDestroy(); Log.i(TAG, onDestroy); }}我們通過記錄操作和打印日志的方式來看看Activity的生命周期過程;
1、 運行
看到如下打印日志:
11-26 09:09:33.665 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onCreate
11-26 09:09:33.665 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStart
11-26 09:09:33.665 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onResume
2、按下返回按鍵:
11-26 09:30:20.097 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onPause
11-26 09:30:20.637 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStop
11-26 09:30:20.637 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onDestroy
3、長按Home鍵,彈出最近打開過的應用程序,點擊ActivityDemo
11-26 09:31:07.341 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onCreate
11-26 09:31:07.341 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStart
11-26 09:31:07.341 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onResume
4、按Home鍵
11-26 09:31:44.649 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onPause
11-26 09:31:45.173 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStop
5、在AllList中點擊打開
11-26 09:32:11.793 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onRestart
11-26 09:32:11.793 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStart
11-26 09:32:11.793 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onResume
通過日志信息,我們可以看到,
電腦資料
《Android Activity 詳述》(http://www.msguai.com)。Activity的啟動過程:onCreate—onStart—onResume;
下返回鍵時:onPause—onStop—onDestroy 正如上面說是,當按下返回鍵時,此Activity彈出棧,程序銷毀。確實如此;
我們再次 打開時的啟動過程又回到onCreate—onStart—onResume。OK;
啟動之后按下Home鍵,回到Launcher,查看打印信息:onPause—onStop;
再次打開的運行過程:onRestart—onStart—onResume;
我們通過對Activity的各種操作,構成了Activity的生命周期,我們看到無論對Activity做如何的操作,都會接收到相關的回調方法,那么我們在開發(fā)的過程中通過這些回調方法就可以寫工作,比如說釋放一些重量級的對象,網絡連接,數據庫連接,文件讀等等。
以下是各個方法的詳細說明:
onCreate():當 activity 第一次創(chuàng)建時會被調用。在這個方法中你需要完成所有的正常靜態(tài)設置 ,比如創(chuàng)建一個視圖( view )、綁定列表的數據等等。如果能捕獲到 activity 狀態(tài)的話,這個方法傳遞進來的 Bundle 對象將存放了 activity 當前的狀態(tài)。調用該方法后一般會調用 onStart() 方法。
onRestart():在 activity 被停止后重新啟動時會調用該方法。其后續(xù)會調用 onStart 方法。
onStart() 當 activity 對于用戶可見前即調用這個方法。如果 activity回到前臺則接著調用 onResume() ,如果 activity 隱藏則調用onStop()
onResume():在 activity 開始與用戶交互前調用該方法。在這時該activity 處于 activity 棧的頂部,并且接受用戶的輸入。其后續(xù)會調用 onPause() 方法。
onPause():在系統(tǒng)準備開始恢復其它 activity 時會調用該方法。這個方法中通常用來提交一些還沒保存的更改到持久數據 中,停止一些動畫或其它一些耗 CPU 的操作等等。無論在該方法里面進行任何操作,都需要較快速完成,因為如果它不返回的話,下一個 activity 將無法恢復出來。如果 activity 返回到前臺將會調用 onResume() ,如果 activity 變得對用戶不可見了將會調用onStop() 。
onStop():在 activity 對用戶不可見時將調用該方法?赡軙驗楫斍 activity 正在被銷毀,或另一個 activity (已經存在的activity 或新的 activity )已經恢復了正準備覆蓋它,而調用該方法。如果 activity 正準備返回與用戶交互時后續(xù)會調用onRestart ,如果 activity 正在被釋放則會調用 onDestroy 。
onDestroy():在 activity 被銷毀前會調用該方法。這是 activity 能接收到的最后一個調用?赡軙驗橛腥苏{用了 finish 方法使得當前activity 正在關閉,或系統(tǒng)為了保護內存臨時釋放這個 activity的實例,而調用該方法。你可以用 isFinishing 方法來區(qū)分這兩種不同的情況。
啟動另外一個 Activity
要啟動一個新的Activity,我們可以通過調用 startActivity來啟動例:Intent intent =new Intent(CurrentActivity.this,OtherActivity.class); startActivity(intent);
注意:OtherActivity同樣在 AndroidManifest.xml 中定義。
Activity 之間通信使用 Intent 通信
在 Android 中,不同的 Activity 實例可能運行在一個進程中,也可能運行在不同的進程中。因此我們需要一種特別的機制幫助我們在 Activity 之間傳遞消息。Android 中通過 Intent 對象來表示一條消息,一個 Intent 對象不僅包含有這個消息的目的地,還可以包含消息的內容,這好比一封 Email,其中不僅應該包含收件地址,還可以包含具體的內容。對于一個 Intent 對象,消息“目的地”是必須的,而內容則是可選項。
在上面的實例中通過Activity. startActivity(intent)啟動另外一個 Activity 的時候,我們在 Intent 類的構造器中指定了“收件人地址”。
我們通過bundle對象來傳遞信息,bundle維護了一個HashMap
Intent intent =new Intent(MainActivity.this,OtherActivity.class); intent.putExtra(boolean_key, true); intent.putExtra(string_key, string_value); startActivity(intent);
接收:
Intent intent=getIntent(); intent.getBooleanExtra(boolean_key,false); intent.getStringExtra(string_key);
Activity 的 Intent Filter
ntent Filter 描述了一個組件愿意接收什么樣的 Intent 對象,Android 將其抽象為 android.content.IntentFilter 類。在 Android 的 AndroidManifest.xml 配置文件中可以通過當程序員使用 startActivity(intent) 來啟動另外一個 Activity 時,如果直接指定 intent 了對象的 Component 屬性,那么 Activity Manager 將試圖啟動其 Component 屬性指定的 Activity。否則 Android 將通過 Intent 的其它屬性從安裝在系統(tǒng)中的所有 Activity 中查找與之最匹配的一個啟動,如果沒有找到合適的 Activity,應用程序會得到一個系統(tǒng)拋出的異常。這個匹配的過程如下:
圖 4. Activity 種 Intent Filter 的匹配過程
Action 匹配
Action 匹配Action 是一個用戶定義的字符串,用于描述一個 Android 應用程序組件,一個 Intent Filter 可以包含多個 Action。在 AndroidManifest.xml 的 Activity 定義時可以在其<intent-filter>……</intent-filter>
如果我們在啟動一個 Activity 時使用這樣的 Intent 對象:
Intent intent =new Intent(); intent.setAction(com.zy.myaction);
那么所有的 Action 列表中包含了“com.zy.myaction”的 Activity 都將會匹配成功。
Android 預定義了一系列的 Action 分別表示特定的系統(tǒng)動作。這些 Action 通過常量的方式定義在android.content. Intent中,以“ACTION_”開頭。我們可以在 Android 提供的文檔中找到它們的詳細說明。
URI 數據匹配
一個 Intent 可以通過 URI 攜帶外部數據給目標組件。在
mimeType 屬性指定攜帶外部數據的數據類型,scheme 指定協(xié)議,host、port、path 指定數據的位置、端口、和路徑。如下:
<data android:host="host" android:mimetype="mimeType" android:path="path/" android:port="port" android:scheme="scheme"></data>
如果在 Intent Filter 中指定了這些屬性,那么只有所有的屬性都匹配成功時 URI 數據匹配才會成功。
Category 類別匹配
一些關于 Activity 的技巧
鎖定 Activity 運行時的屏幕方向
Android 內置了方向感應器的支持。在 G1 中,Android 會根據 G1 所處的方向自動在豎屏和橫屏間切換。但是有時我們的應用程序僅能在橫屏 / 豎屏時運行,比如某些游戲,此時我們需要鎖定該 Activity 運行時的屏幕方向,節(jié)點的android:screenOrientation屬性可以完成該項任務,示例代碼如下:
// 豎屏 , 值為 landscape 時為橫屏…………
全屏的 Activity
要使一個 Activity 全屏運行,可以在其onCreate()方法中添加如下代碼實現:
// 設置全屏模式 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 去除標題欄 requestWindowFeature(Window.FEATURE_NO_TITLE);
設置Activity 的 Title
setTitle(我的);
實現雙擊返回鍵退出功能:
private long exitTime = 0;@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN){ if((System.currentTimeMillis()-exitTime) > 2000){ Toast.makeText(getApplicationContext(), 再按一次退出程序, Toast.LENGTH_SHORT).show(); exitTime = System.currentTimeMillis(); } else { finish(); System.exit(0); } return true; } return super.onKeyDown(keyCode, event);}