前言
作為Android的四大組件之一,Activity占據(jù)著非常重要的作用。本文將圍繞Android的生命周期、啟動模式、基本配置等方面進行介紹。本文知識來源于各類技術(shù)書籍以及博客,文章末尾已經(jīng)列出。
簡介
應(yīng)用程序的每一個界面都是一個Activity,所以也有人稱其為視圖界面。從字面的意思去理解,Activity具有活動的意思,我們在應(yīng)用中進行的操作都是集中在Activity上面完成,例如撥號、拍照、發(fā)送email、看地圖。每一個activity被給設(shè)置到一個窗口,在上面可以繪制交互界面。窗口通常充滿屏幕,也可以小于屏幕而浮于其它窗口之上,如浮動圓角對話框Activity。
一個應(yīng)用程序通常由多個activities組成,他們通常是松耦合關(guān)系,通常一個應(yīng)用程序包含有一個主Activity,即點擊桌面圖標的時候首先進入的Activity。
Android創(chuàng)建與啟動
以一個簡單的Activity的創(chuàng)建與使用示說明:
創(chuàng)建
public class MainActivity extends Activity {
Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button) findViewById(R.id.button1);
}
}
通過集成Activity類完成新建Activity,并且至少需要重寫onCreate方法。在onCreate中,通過setContentView為Activity設(shè)置布局。
注冊Activity
在manifest中注冊Activity
<activity
android:name=".activity.MainActivity"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:launchMode="standard" >
<intent-filter>
<action android:name="myaction2"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Activity必須在AndroidManifest.xml注冊,如果沒有注冊,這個Activity就不能正常運行。
其中如果在<intent-filter>中指定
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
表明這個Activity是主Activity,在Android系統(tǒng)點擊應(yīng)用圖標首先進入主Activity。
啟動Activity
Activity是通過Intent用來在應(yīng)用程序的Activity間啟動、停止和傳輸。
啟動Activity的三種方法:
1、顯示啟動
在當(dāng)前Activity啟動Activity2
Intent intent = new Intent(this , Activity2.class);
startActivity(intent);
2、隱式啟動
若Activity2在AndroidManifest.xml文件中配置intent-filter的action和category、data,如下:
<intent-filter>
<action android:name="myaction2"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="mycategory" />
</intent-filter>
那么可以通過如下方式啟動Activity2:
Intent intent = new Intent("myaction2");
startActivity(intent);
這樣就可以啟動Activity2
注:在使用intent隱式調(diào)用Activity時會遇到多個Activity的intent-filter中的action和category相同時,這時android會先彈出一個選擇界面的窗口,顯式要啟動的Activity列表,根據(jù)用戶的選擇來啟動Activity,如Activity2和Activity3的action和category相同
3、默認啟動
通過桌面圖標點擊應(yīng)用圖標進入程序的第一個Activity,因其啟動方式有別上述兩個方式,將其劃分為第三類的啟動方式。
若Activity在AndroidManifest.xml文件的intent-filter的action和category,如下:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
那么,點擊桌面的應(yīng)用圖標即可啟動Activity。
注:如果在N個Activity中都配置上述的action和category,那么桌面會有N個應(yīng)用的圖標,點擊不同的圖標會進入對應(yīng)的Activity。
Activity切換動畫
Android的生命周期
接下來給各位介紹Activity的生命周期,如下圖
我覺得上面這張圖更加讓人理解Android的生命周期,大家不妨對比著看。
詳細的生命周期可以點此查看
(1) onCreate
表示Activity正在被創(chuàng)建,這是第一個執(zhí)行的方法,在Activity的生命周期中只執(zhí)行一次。在這個方法中做一些初始化工作,比如調(diào)用setContentView去加載界面布局,初始化Activity所需要的數(shù)據(jù)等。后續(xù)的方法是onStart
(2) onRestart
表示Activity正在重新啟動,一般情況下,當(dāng)前的Activity從不可見的狀態(tài)變?yōu)榭梢姞顟B(tài)時,onRestart就會被調(diào)用。這種情形一般是用戶操作出現(xiàn)所致,比如用戶按Home鍵回到桌面或者用戶打開了一個新的Activity,這時候Activity就會暫停,接著用戶又回到該Activity。后續(xù)方法是onStart
(2) onStart
表示Activity正在被啟動,即將開始。這個時候Activity是可見的,但是還沒有出現(xiàn)在前臺,不能和用戶進行交互。這個時候可以理解為Activity已經(jīng)顯示出來,但是我們還看不到。后續(xù)的方法是onResume
(4) onResume
表示Activity可見,并且已經(jīng)出現(xiàn)在前臺并開始活動,能和用戶正常進行交互。需要注意的是onStart和onResume的區(qū)別,二者都是Activity可見,但是onStart時Activity還在后臺,而onResume時Activity到了前臺了,這時候可以開啟動畫或者獲取獨占性設(shè)備的操作如打開相機、獲取麥克風(fēng)等。
(5) onPause
表示Activity由前臺轉(zhuǎn)到后臺,正常情況下,緊接著onStop就會被調(diào)用。這時仍然可見。如果這時候快速地回到當(dāng)前Activity,那么onResume會被調(diào)用,這類情況屬于極端情況,用戶操作很難重現(xiàn)這一場景。此時可以做一些存儲數(shù)據(jù),停止動畫等操作,但是注意不能太耗時,如果太耗時會影響到新的Activity的顯示。onPause是先執(zhí)行完,新的Activity的onCreate才會執(zhí)行。onResume和onPause相對應(yīng)。
(6) onStop
表示Activity即將停止,當(dāng)前的Activity對用戶不在可見。可稍微做些重量級的回收操作。后續(xù)的操作可能是onRestart或者onDestroy或者一直保持這個狀態(tài)。
(7) onDestory
表示Activity正在被銷毀,是生命周期的最后一個回調(diào),也是只調(diào)用一次。發(fā)生的條件是Activity本身已經(jīng)執(zhí)行完畢,或者系統(tǒng)資源不足需要回收資源將Activity銷毀。
我們考慮如下幾類情況:
1、當(dāng)一個Toast彈出的時候,會發(fā)生回調(diào)么?
No
2、當(dāng)一個AlertDialog彈出的時候,會發(fā)生回調(diào)么?
No, 如果AlertDialog獲取焦點,Activity會觸發(fā)onWindowFocusChanged回調(diào)
3、當(dāng)一個PopWindow彈出的時候,會發(fā)生回調(diào)么?
No, 如果PopWindow獲取焦點,如mPopupWindow.setFocusable(true),Activity會觸發(fā)onWindowFocusChanged回調(diào)。
4.橫豎屏切換時,會造成Activity被銷毀然后重新創(chuàng)建。若在Activity配置android:configChanges="orientation",橫豎屏切換時,只觸發(fā)onConfigurationChanged( )回調(diào),Activity不會被重新創(chuàng)建。
啟動模式
Activity有四種不同的啟動模式,不同的模式,對應(yīng)著Activity對象創(chuàng)建與復(fù)用策略各有特點,可以在Manifest中配置啟動模式
<activity android:name="cn.iterlog.xmimagepicker.videoplay.VideoActivity"
android:theme="@style/ImageTheme"
android:launchMode="singleInstance"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
首先先了解兩個概念Task和Back Stack。
Task和Back Stack
Task:用于提供給用戶操作完成一項任務(wù)的Activity集合,注意Activity可以來自不同的App,同一個App的Activity也可能在不同的Task重
Back Stack(回退棧): 管理著Task中所有的Activity的Stack(棧), 遵循后進先出原則。
處于Back Stack的最低部的Activity被稱作根Activity。
一般情況下,當(dāng)前Activity A啟動新的Activity B的時候,B會入棧,處于回退棧最頂端,并獲取焦點。A位于棧中,處于stop的狀態(tài)。如果用戶點擊后退鍵或者B調(diào)用finish()方法,那么B被出棧,B的onDestroy被調(diào)用,整體銷毀。A重新獲取焦點,進入前臺。
Task里面的Activity嚴格按照"后進先出"的方式進行管理,他們的順序不會發(fā)生改變。下圖展示了Activity的新建和退出時,回退棧的變化。
如果Task的棧頂Activity處于前臺狀態(tài),Task也是處于前臺狀態(tài)。
如果Task的棧頂Activity處于后臺狀態(tài),Task也處于后臺狀態(tài)。
用戶在使用應(yīng)用的時候點擊Home鍵,Task則由前臺轉(zhuǎn)入后臺,用戶之后點擊桌面啟動圖標,再次啟動應(yīng)用,那么此時Task由后臺轉(zhuǎn)入前臺頁面。
四種啟動模式
正常情況下,啟動多個相同Activity的時候會默認新建多個對象,并將他們?nèi)霔!F鋵嵤菦]有必要為Activity創(chuàng)建這么多相同的對象的,Android在設(shè)計的時候也考慮到這個問題,所以提供了四種啟動模式。
standard
系統(tǒng)默認模式,每次啟動一個Activity都會重新創(chuàng)建一個新的實例,而不管Activity是否已經(jīng)創(chuàng)建了一個實例。
singleTop
棧頂復(fù)用模式,系統(tǒng)啟動時,系統(tǒng)會啟動當(dāng)前棧頂Activity是不是要啟動的Activity,如果是則不需要創(chuàng)建新的Activity而直接引用這個Activity,如果不是那么創(chuàng)建新的Activity。系統(tǒng)會回調(diào)onNewIntent的方法。
singleTask
棧內(nèi)復(fù)用模式,如果棧內(nèi)已經(jīng)存在了一個Activity的實例,那么Activity不會被重新創(chuàng)建,同時他的onNewIntent方法會被回調(diào),并將該Activity實例置于棧頂,原先處于該實例頂部的Activity實例會被出棧銷毀。如果是其他程序啟動Activity,那么它會重新創(chuàng)建一個任務(wù)棧。
singleInstance
單實例模式,是singleTask的加強版,具有singleTask所有特點,并且此種模式下Activity只有一個實例,并且只能單獨的存在一個任務(wù)棧中。
通過Intent啟動Activity的時候,可以通過添加標志位的啟動方式。
Intent intent = new Intent(this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Intent.FLAG_ACTIVITY_NEW_TASK
使用一個新的Task來啟動Activity,但每個Activity都將在一個新的Task中。該Flag通常使用在Service重啟動Activity的場景。
Intent.FLAG_ACTIVITY_SINGLE_TOP
使用singleTop模式來啟動一個Activity
Intent.FLAG_ACTIVITY_CLEAR_TOP
使用singleTask模式來啟動一個Activity
Intent.FLAG_ACTIVITY_NO_HISTORY
使用singleTask模式來啟動一個Activity
使用這種方式啟動Activity,當(dāng)Activity啟動其他Activity的時候,該Activity會被銷毀,不入棧。
資料來源
[1].https://developer.android.com/guide/components/activities.html
[2].http://www.cnblogs.com/tekkaman/archive/2011/06/07/2074211.html
[3].http://blog.csdn.net/guxiao1201/article/details/41517567
[4].安卓群英傳.徐宜生.電子工業(yè)出版社.2015
[5].安卓開發(fā)藝術(shù)探索.任玉剛.電子工業(yè)出版社.2015
[6].http://www.lxweimin.com/p/d4d677727a0a