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