一. Activity生命周期
簡單說明一下Activity每個(gè)生命周期函數(shù):
onCreate():
表示Activity正在被創(chuàng)建,這是Activity生命周期的第一個(gè)方法
onStart():
表示Activity正在被啟動,這時(shí)候的Activity已經(jīng)被創(chuàng)建好了,完全過了準(zhǔn)備階段,但是沒有出現(xiàn)在前臺,需要執(zhí)行onResume()函數(shù)才可以進(jìn)入到前臺與用戶進(jìn)行交互。
onResume():
表示Activitiy已經(jīng)可見了,并且Activity處于運(yùn)行狀態(tài),也就是Activity不止出現(xiàn)在了前臺,而且還可以讓用戶點(diǎn)擊,滑動等等操作與它進(jìn)行交互。
onPause(): (注意)
onPause被觸發(fā),并不是Activity的主界面處于被其它東西不完全覆蓋狀態(tài),而是被某個(gè)其它Activity不完全覆蓋。
onStop():
表示Activity即將停止,我們程序員應(yīng)該在此函數(shù)中做一些不那么耗時(shí)的輕量級回收操作。
onRestart():
表示Activity正在重新啟動。一般情況下,一個(gè)存在于后臺不可見的Activity變?yōu)榭梢姞顟B(tài),都會去執(zhí)行onRestart()函數(shù),然后會繼續(xù)執(zhí)行onStart()函數(shù),onResume()函數(shù)出現(xiàn)在前臺并且處于運(yùn)行狀態(tài)。
onDestory():
表示Activity要被銷毀了。這是Activity生命中的最后一個(gè)階段,我們可以在onDestory()函數(shù)中做一些回收工作和資源釋放等,比如:廣播接收器的注銷等。
Activity常見幾種狀態(tài)的生命周期分析
Activity啟動–>onCreate()–>onStart()–>onResume()
點(diǎn)擊home鍵回到桌面–>onPause()–>onStop()
再次回到原Activity時(shí)–>onRestart()–>onStart()–>onResume()
退出當(dāng)前Activity時(shí)–>onPause()–>onStop()–>onDestroy()
二 android 任務(wù)棧
參考地址:http://blog.csdn.net/javazejian/article/details/52071885
1. android任務(wù)棧特點(diǎn)
(1) android任務(wù)棧又稱為Task,它是一個(gè)棧結(jié)構(gòu),具有后進(jìn)先出的特性,用于存放我們的Activity組件。
(2) 我們每次打開一個(gè)新的Activity或者退出當(dāng)前Activity都會在一個(gè)稱為任務(wù)棧的結(jié)構(gòu)中添加或者減少一個(gè)Activity組件,因此一個(gè)任務(wù)棧包含了一個(gè)activity的集合, android系統(tǒng)可以通過Task有序地管理每個(gè)activity,并決定哪個(gè)Activity與用戶進(jìn)行交互:只有在任務(wù)棧棧頂?shù)腶ctivity才可以跟用戶進(jìn)行交互。
(3) 在我們退出應(yīng)用程序時(shí),必須把所有的任務(wù)棧中所有的activity清除出棧時(shí),任務(wù)棧才會被銷毀。當(dāng)然任務(wù)棧也可以移動到后臺, 并且保留了每一個(gè)activity的狀態(tài). 可以有序的給用戶列出它們的任務(wù), 同時(shí)也不會丟失Activity的狀態(tài)信息。
(4) 需要注意的是,一個(gè)App中可能不止一個(gè)任務(wù)棧,某些特殊情況下,單獨(dú)一個(gè)Actvity可以獨(dú)享一個(gè)任務(wù)棧。還有一點(diǎn)就是一個(gè)Task中的Actvity可以來自不同的App,同一個(gè)App的Activity也可能不在一個(gè)Task中。
2. taskAffinity屬性,一個(gè)APP引用多個(gè)任務(wù)棧(下面singTask特殊場景用到)
(1). TaskAffinity 參數(shù)標(biāo)識著Activity所需要的任務(wù)棧的名稱,默認(rèn)情況下,一個(gè)應(yīng)用中所有Activity所需要的任務(wù), 棧名稱都為該應(yīng)用的包名。
(1). TaskAffinity 屬性一般跟singleTask模式或者跟allowTaskReparenting屬性結(jié)合使用,在其他情況下沒有實(shí)際意義。
(3). TaskAffinity屬性的值不能與當(dāng)前應(yīng)用包名相同,否則其值跟作廢沒兩樣。
使用方法:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="comzejian.myapplication">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ActivityA"
android:launchMode="singleTask"
android:taskAffinity="com.zejian.singleTask.affinity"/>
</application>
</manifest>
我們可以通過singleTask與android:taskAffinity屬性相結(jié)合的方式來指定我們Activity所需要的棧名稱,使相應(yīng)的Activity存在于不同的棧中,圖解如下:

3. allowTaskReparenting屬性
(1) 主要作用是activity的遷移,即從一個(gè)task遷移到另一個(gè)task,這個(gè)遷移跟activity的taskAffinity有關(guān)。
(2) 使用方法:
<activity android:name=".ActivityC"
android:allowTaskReparenting="true">
</activity>
(3) 使用過程圖解:

說明:如果allowTaskReparenting值為false時(shí),ActivityC并不會直接從A應(yīng)用的任務(wù)棧遷移到B應(yīng)用的任務(wù)棧,而是B應(yīng)用直接重新創(chuàng)建了ActivityC的實(shí)例
注意:allowTaskReparenting僅限于singleTop和standard模式
例:TaskAffinity與singleTask應(yīng)用場景
??假如現(xiàn)在有這么一個(gè)需求,我們的客戶端app正處于后臺運(yùn)行,此時(shí)我們因?yàn)槟承┬枰?,讓微信調(diào)用自己客戶端app的某個(gè)頁面,用戶完成相關(guān)操作后,我們不做任何處理,按下回退或者當(dāng)前Activity.finish(),頁面都會停留在自己的客戶端(此時(shí)我們的app回退棧不為空),這顯然不符合邏輯的,用戶體驗(yàn)也是相當(dāng)出問題的。我們要求是,回退必須回到微信客戶端,而且要保證不殺死自己的app.這時(shí)候我們的處理方案就是,設(shè)置當(dāng)前被調(diào)起Activity的屬性為:
LaunchMode=""SingleTask" taskAffinity="com.tencent.mm"
4.清空任務(wù)棧
清空任務(wù)棧的方法,在一般情況下我們只需要在<activity>標(biāo)簽中指明相應(yīng)的屬性值即可。
(1) android:clearTaskOnLaunch .
這個(gè)屬性用來標(biāo)記是否從task清除除根Activity之外的所有的Activity,“true”表示清除,“false”表示不清除,默認(rèn)為“false”。
注意的,這個(gè)屬性只對任務(wù)棧內(nèi)的root Activity起作用,任務(wù)棧內(nèi)其他的Activity都會被忽略。
例如:一個(gè)應(yīng)用的Activity A,B,C。 A跳轉(zhuǎn)B,B跳轉(zhuǎn)C,點(diǎn)擊HOME,再在桌面點(diǎn)擊圖標(biāo),結(jié)果只能看到A,如下圖所示:

情況1 當(dāng):ActivityA的clearTaskOnLaunch = true的時(shí)候,只要ActivityA沒有finish(),其它的Activity設(shè)置clearTaskOnLaunch屬性全部沒用。假如ActivityA.finish(),任務(wù)棧最底部Activity設(shè)置clearTaskOnLaunch有效。
情況2 當(dāng):ActivityA的clearTaskOnLaunch = false的時(shí)候,無論ActivityA有沒有被finish(),其它的Activity設(shè)置clearTaskOnLaunch屬性全部沒用。
如下圖: clearTaskOnLaunch2.png

(2)android:finishOnTaskLaunch
這個(gè)屬性是作用在自己身上(把自己移除任務(wù)棧,不影響別的Activity).
把ActivityB的android:finishOnTaskLaunch = true時(shí),點(diǎn)擊HOME,再在桌面點(diǎn)擊圖標(biāo)進(jìn)入APP,此時(shí)任務(wù)棧里已經(jīng)沒有ActivityB了。如下圖:

(3)android:alwaysRetainTaskState
alwaysRetainTaskState實(shí)際上是給了當(dāng)前Activity所在的任務(wù)棧一個(gè)“免死金牌”,如果當(dāng)前Activity的android:alwaysRetainTaskState設(shè)置為true時(shí),那么該Activity所在的任務(wù)棧將不會受到任何清理命令的影響,一直保持當(dāng)前任務(wù)棧的狀態(tài)。
默認(rèn)任務(wù)棧的缺點(diǎn):
(1)每開啟一次頁面都會在任務(wù)棧中添加一個(gè)Activity,而只有任務(wù)棧中的Activity全部清除出棧時(shí),任務(wù)棧被銷毀,程序才會退出,這樣就造成了用,戶體驗(yàn)差, 需要點(diǎn)擊多次返回才可以把程序退出了。
(2)每開啟一次頁面都會在任務(wù)棧中添加一個(gè)Activity還會造成數(shù)據(jù)冗余, 重復(fù)數(shù)據(jù)太多, 會導(dǎo)致內(nèi)存溢出的問題(OOM)。
為了解決任務(wù)棧的缺點(diǎn),我們引入了啟動模式。
三 Activity啟動模式
參考地址:http://blog.csdn.net/javazejian/article/details/52071885
Activity的4種啟動模式(standard,singleTop,singTask和singleInstance)
1. Standard 模式
又稱為標(biāo)準(zhǔn)模式,也是系統(tǒng)的默認(rèn)模式(可以不指定),在這樣模式下,每啟動一個(gè)Activity都會重新創(chuàng)建一個(gè)Activity的新實(shí)例,并且將其加入任務(wù)棧中,而且完全不會去考慮這個(gè)實(shí)例是否已存在。我們通過圖解來更清晰地了解Standard模式:

通過上圖,我們可以發(fā)現(xiàn),這個(gè)過程中,在standard模式下啟動了三次MainActivity后,都生成了不同的新實(shí)例,并添加到同一個(gè)任務(wù)棧中。這個(gè)時(shí)候Activity的onCreate、onStart、onResume方法都會被調(diào)用。
2. singleTop 模式
又稱棧頂復(fù)用模式,顧名思義,在這種模式下,如果有新的Activity已經(jīng)存在任務(wù)棧的棧頂,那么此Activity就不會被重新創(chuàng)建新實(shí)例,而是復(fù)用已存在任務(wù)棧棧頂?shù)腁ctivity。這里重點(diǎn)是位于棧頂,才會被復(fù)用,如果新的Activity的實(shí)例已存在但沒有位于棧頂,那么新的Activity仍然會被重建。需要注意的是,Activity的onNewIntent方法會被調(diào)用,方法原型如下:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
通過此方法的參數(shù),我們可以獲取當(dāng)前請求的相關(guān)信息,此時(shí)Activity的onCreate、onStart方法不會被調(diào)用,因?yàn)锳ctivity并沒有被重建。同理,我們通過圖解來協(xié)助我們更清晰的理解singleTop模式:

從上圖我們可以看出,當(dāng)需要新創(chuàng)建的MainActivity位于棧頂時(shí),MainActivity并沒有重新創(chuàng)建。下面我們再來看看新創(chuàng)建的MainActivity沒有位于棧頂?shù)那闆r。

從圖中可以看出,當(dāng)我們再次啟動MainActivity時(shí),由于MainActivity位于棧中,所以系統(tǒng)直接將其置于棧頂,并移除其上方的所有Activity。當(dāng)然如果所需要的MainActivity不存在棧中,則會創(chuàng)建新的Activity并添加到棧中。singleTask 模式比較適合應(yīng)用的主界面activity(頻繁使用的主架構(gòu)),可以用于主架構(gòu)的activity,(如新聞,側(cè)滑,應(yīng)用主界面等)里面有好多fragment,一般不會被銷毀,它可以跳轉(zhuǎn)其它的activity 界面再回主架構(gòu)界面,此時(shí)其他Activity就銷毀了。當(dāng)然singTask還有一些比較特殊的場景這個(gè)我們后面會一一通過情景代碼分析。
3. singleTask 模式
又稱為棧內(nèi)復(fù)用模式。這是一種單例模式,與singTop點(diǎn)類似,只不過singTop是檢測棧頂元素是否有需要啟動的Activity,而singTask則是檢測整個(gè)棧中是否存在當(dāng)前需要啟動的Activity,如果存在就直接將該Activity置于棧頂,并將該Activity以上的Activity都從任務(wù)棧中移出銷毀,同時(shí)也會回調(diào)onNewIntent方法。情況如下圖:

從圖中可以看出,當(dāng)我們再次啟動MainActivity時(shí),由于MainActivity位于棧中,所以系統(tǒng)直接將其置于棧頂,并移除其上方的所有Activity。當(dāng)然如果所需要的MainActivity不存在棧中,則會創(chuàng)建新的Activity并添加到棧中。singleTask 模式比較適合應(yīng)用的主界面activity(頻繁使用的主架構(gòu)),可以用于主架構(gòu)的activity,(如新聞,側(cè)滑,應(yīng)用主界面等)里面有好多fragment,一般不會被銷毀,它可以跳轉(zhuǎn)其它的activity 界面再回主架構(gòu)界面,此時(shí)其他Activity就銷毀了。
singleTask 特殊場景
現(xiàn)在我們假設(shè)有如下兩個(gè)Task棧,分別為前臺任務(wù)棧和后臺任務(wù)棧,如下圖:

情況一:
此時(shí)我們先啟動CD,然后再啟動AB,再有B啟動D,此時(shí)后臺任務(wù)棧便會被切換到前臺,而且這個(gè)時(shí)候整個(gè)后退列表就變成了ABCD,請注意我們這里強(qiáng)調(diào)的是后退列表,而非棧合并。因此當(dāng)用戶點(diǎn)擊back鍵時(shí),列表中的Activity會依次按DCBA順序出棧,如下圖所示:

情況二:
如果上面B請求啟動C,那么又會是什么情況呢?其實(shí)這個(gè)時(shí)候任務(wù)棧退出列表變成C->B->A,其實(shí)原因很簡單,singleTask模式的ActivityC切換到棧頂時(shí)會導(dǎo)致在他之上的棧內(nèi)的Activity出棧,如下圖:

4. singleInstance 模式
在singleInstance模式下,該Activity在整個(gè)android系統(tǒng)內(nèi)存中有且只有一個(gè)實(shí)例,而且該實(shí)例單獨(dú)尊享一個(gè)Task。換句話說,A應(yīng)用需要啟動的MainActivity 是singleInstance模式,當(dāng)A啟動后,系統(tǒng)會為它創(chuàng)建一個(gè)新的任務(wù)棧,然后A單獨(dú)在這個(gè)新的任務(wù)棧中,如果此時(shí)B應(yīng)用也要激活MainActivity,由于棧內(nèi)復(fù)用的特性,則不會重新創(chuàng)建,而是兩個(gè)應(yīng)用共享一個(gè)Activity的實(shí)例。如下圖所示:

從圖中我們可以看到最終AB應(yīng)用都共享一個(gè)singleInstance模式的MainActivity,也沒有去重新創(chuàng)建。到此Activity的四種啟動模式我們都介紹完了,下面我們接著來聊聊怎么使用啟動模式。
Activity啟動模式的使用方式
1.通過AndroidMenifest.xml文件為Activity指定啟動模式,代碼如下:
<activity android:name=".ActivityC" android:launchMode="singleTask" />
2.通過在Intent中設(shè)置標(biāo)志位(addFlags方法)來為Activity指定啟動模式,示例代碼如下:
Intent intent = new Intent();
intent.setClass(ActivityB.this,ActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Flags對應(yīng)的值
Intent.FLAG_ACTIVITY_SINGLE_TOP
??該標(biāo)志位表示使用singleTop模式來啟動一個(gè)Activity,與在清單文件指定android:launchMode="singleTop"效果相同。
Intent.FLAG_ACTIVITY_CLEAR_TOP
該標(biāo)志位表示使用singleTask模式來啟動一個(gè)Activity,與在清單文件指定android: launchMode="singleTask"效果相同。
Intent.FLAG_ACTIVITY_NO_HISTORY
??使用該模式來啟動Activity,當(dāng)該Activity啟動其他Activity后,該Activity就被銷毀了,不會保留在任務(wù)棧中。如A-B,B中以這種模式啟動C,C再啟動D,則任務(wù)棧只有ABD。
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
??使用該標(biāo)識位啟動的Activity不添加到最近應(yīng)用列表,也即我們從最近應(yīng)用里面查看不到我們啟動的這個(gè)activity。與屬性android:excludeFromRecents="true"效果相同。
四. scheme跳轉(zhuǎn)協(xié)議(簡單的應(yīng)用)
Android中的scheme是一種頁面內(nèi)跳轉(zhuǎn)協(xié)議,通過自定義scheme協(xié)議,可以非常方便的跳轉(zhuǎn)到app中的各個(gè)頁面,通過scheme協(xié)議,服務(wù)器可以定制化告訴app跳轉(zhuǎn)到哪個(gè)頁面,可以通過通知欄消息定制化跳轉(zhuǎn)頁面,可以通過H5頁面跳轉(zhuǎn)到相應(yīng)頁面等等。
目前主要用于以下幾種場景:
(1) 服務(wù)器下發(fā)跳轉(zhuǎn)路徑,客戶端根據(jù)服務(wù)器下發(fā)跳轉(zhuǎn)路徑跳轉(zhuǎn)相應(yīng)的頁面;
(2) H5頁面點(diǎn)擊錨點(diǎn),根據(jù)錨點(diǎn)具體跳轉(zhuǎn)路徑App端跳轉(zhuǎn)具體的頁面;
(3) App端收到服務(wù)器端下發(fā)的PUSH通知欄消息,根據(jù)消息的點(diǎn)擊跳轉(zhuǎn)路徑跳轉(zhuǎn)相關(guān)頁面
scheme協(xié)議跳轉(zhuǎn)的一個(gè)完整實(shí)例
第一步:在Mainefest配置文件中配置需要用scheme協(xié)議跳轉(zhuǎn)的Activity
<!-- scheme協(xié)議 -->
<activity
android:name=".SchemeActivity"
android:label="@string/app_name">
<!-- 要想在別的App上能成功調(diào)起App,必須添加intent過濾器 -->
<!-- 協(xié)議部分,隨便設(shè)置 -->
<intent-filter>
<!--協(xié)議部分,隨便設(shè)置-->
<data android:scheme="scheme" android:host="mtime" android:path="/goodsDetail" />
<!--下面這幾行也必須得設(shè)置-->
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
第二步:模擬從網(wǎng)絡(luò)中獲取scheme協(xié)議的url,跳轉(zhuǎn)到指定Activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// (1)在manifest配置文件中配置了scheme參數(shù)
// (2)網(wǎng)絡(luò)端獲取url
// (3)跳轉(zhuǎn)
String url = "scheme://mtime/goodsDetail?goodsId=10011002";
Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse(url));
startActivity(intent);
}
}
第三步:獲取scheme協(xié)議參數(shù)
public class SchemeActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scheme);
//獲取參數(shù)
Uri data = getIntent().getData();
Log.i(TAG, "host = " + data.getHost() + " path = " + data.getPath() + " query = " + data.getQuery());
String param = data.getQueryParameter("goodsId");
}
}