一、簡介

Activity是Android四大組件之一,對應(yīng)著應(yīng)用的一個(gè)個(gè)界面。Activity實(shí)現(xiàn)了Window.Callback和KeyEvent.Callback兩個(gè)接口,所以用戶通過屏幕點(diǎn)擊或點(diǎn)擊按鍵可以和Activity交互。
創(chuàng)建Activity就是繼承Activity創(chuàng)建子類,必須在清單文件注冊。
二、使用
1. 創(chuàng)建Activity
/**
* 繼承Activity,創(chuàng)建子類
*/
public class MainActivity extends Activity {
/**
* 生命周期方法:首次創(chuàng)建Activity時(shí)調(diào)用,可以做一些初始化工作。始終后接 onStart()
* 必須重寫,需要通過setContentView()設(shè)置界面
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 設(shè)置布局
setContentView(R.layout.activity_main);
// The activity is being created.
}
/**
* 生命周期方法:正在啟動(dòng)Activity,在 Activity 即將對用戶可見之前調(diào)用。如果 Activity
* 轉(zhuǎn)入前臺,則后接 onResume(),如果 Activity轉(zhuǎn)入隱藏狀態(tài),則后接 onStop()
*/
@Override
protected void onStart() {
super.onStart();
// The activity is about to become visible.
}
/**
* 生命周期方法:Activity已經(jīng)啟動(dòng),在 Activity即將開始與用戶進(jìn)行交互之前調(diào)用。始終后接 onPause()
*/
@Override
protected void onResume() {
super.onResume();
// The activity has become visible (it is now "resumed").
}
/**
* 生命周期方法:正在停止,當(dāng)系統(tǒng)即將開始繼續(xù)另一個(gè) Activity 時(shí)調(diào)用。
* 不能做耗時(shí)操作,因?yàn)楸仨毾葓?zhí)行完舊Activity的onPause(),才能執(zhí)行新Activity的onResume()。
* 如果 Activity 返回前臺,則后接 onResume(),如果 Activity 轉(zhuǎn)入對用戶不可見狀態(tài),則后接 onStop()
*/
@Override
protected void onPause() {
super.onPause();
// Another activity is taking focus (this activity is about to be "paused").
}
/**
* 生命周期方法:即將停止,在 Activity 對用戶不再可見時(shí)調(diào)用。
* 可以做一些重量級的回收操作,同樣不能太耗時(shí)。
* 如果 Activity 恢復(fù)與用戶的交互,則后接 onRestart(),如果 Activity 被銷毀,則后接 onDestroy()。
*/
@Override
protected void onStop() {
super.onStop();
// The activity is no longer visible (it is now "stopped")
}
/**
* 生命周期方法:即將銷毀,在 Activity 被銷毀前調(diào)用。做一些最終的資源釋放
*/
@Override
protected void onDestroy() {
super.onDestroy();
// The activity is about to be destroyed.
}
/**
* 生命周期方法:正在重新啟動(dòng)Activity,在 Activity 已停止并即將再次啟動(dòng)前調(diào)用。始終后接 onStart()
*/
@Override
protected void onRestart() {
super.onRestart();
}
}
2. 編寫界面
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Activity"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
3. 清單文件注冊
<application>
...
<!--launchMode啟動(dòng)模式-->
<activity android:name=".MainActivity" android:launchMode="singleTask">
<intent-filter>
<!--指示這是主要入口點(diǎn),且不要求輸入任何 Intent 數(shù)據(jù)-->
<action android:name="android.intent.action.MAIN" />
<!--指示此 Activity 的圖標(biāo)應(yīng)放入系統(tǒng)的應(yīng)用啟動(dòng)器,未設(shè)置icon,則使用application標(biāo)簽下的icon-->
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
...
</application>
4. 啟動(dòng)Activity
上面的Activity,因?yàn)樵O(shè)置了上面的filter,標(biāo)識了是程序的入口,安裝到手機(jī)上后,打開程序,就會為我們啟動(dòng)上面這個(gè)MainActivity。
重復(fù)上面步驟,創(chuàng)建SecondActivity,清單文件注冊。
<activity android:name=".SecondActivity">
<!--隱式啟動(dòng)時(shí)設(shè)置-->
<intent-filter>
<action android:name="acom.test.activity" />
<!--為了能接受隱式啟動(dòng),必須添加,DEFAULT-->
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
- 顯示啟動(dòng)
startActivity(new Intent(MainActivity.this, SecondActivity.class));
- 隱式啟動(dòng)
// intent,設(shè)置action,action是自定義的字符串
Intent intent = new Intent("com.test.activity");
startActivity(intent);
- 帶返回值的啟動(dòng)
// MainActivity啟動(dòng)SecondActivity
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
// 方法不同
startActivityForResult(intent,1);
// SecondActivity返回?cái)?shù)據(jù)
Intent intent = new Intent(this,MainActivity.class);
intent.putExtra("test","返回的數(shù)據(jù)");
setResult(RESULT_OK,intent);
/**
* 重寫Activity的該方法,接收返回?cái)?shù)據(jù)
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
// 判斷請求碼
switch (requestCode){
case 1:
// 判斷返回碼
if(resultCode == RESULT_OK){
String test = data.getStringExtra("test");
Log.e("MainActivity",test); // 將會輸出 “返回的數(shù)據(jù)”
}
break;
}
}
startActivity()本質(zhì)也是調(diào)用startActivityForResult():
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
三、詳解生命周期
1. 7個(gè)生命周期

小知識:
- onStart()和onStop()是從Activity是否可見的角度來回調(diào)的,onResume()和onPause()是從Activity是否位于前臺的角度回調(diào)的
2.Dialog、Popupwindow 和 Toast 不會對Activity的生命周期造成影響,可以仔細(xì)品讀上面onPause()生命周期的解讀,個(gè)人理解是Activity之間的相互切換才會導(dǎo)致生命周期方法的回調(diào)
2. 2個(gè)最常用的生命周期方法
onCreate()
是必須實(shí)現(xiàn)的,用來初始化Activity,通過setContentView()來使用布局資源定義UIonPause()
用來在用戶離開時(shí)保存或提交數(shù)據(jù)
3. 3種生命周期階段
完整生命周期:發(fā)生在 onCreate() 調(diào)用與 onDestroy() 調(diào)用之間。
可見生命周期: 發(fā)生在 onStart() 調(diào)用與 onStop() 調(diào)用之間。在這段時(shí)間,用戶可以在屏幕上看到 Activity 。
前臺生命周期: 發(fā)生在 onResume() 調(diào)用與 onPause() 調(diào)用之間。在這段時(shí)間,Activity 位于屏幕上的所有其他 Activity 之前,并具有用戶輸入焦點(diǎn)。
4. 3種存在狀態(tài)
運(yùn)行
onResume()執(zhí)行后,此 Activity 位于屏幕前臺并具有用戶焦點(diǎn)。暫停
onPause()執(zhí)行后,另一個(gè) Activity 位于屏幕前臺并具有用戶焦點(diǎn),但此 Activity 仍可見。比如:被一個(gè)透明背景的Activity或一個(gè)dialog樣式的Activity覆蓋停止
onStop()執(zhí)行后,該 Activity 被另一個(gè) Activity 完全遮蓋(該 Activity 目前位于“后臺”)。
小知識:
- 死亡: onDestory()執(zhí)行后 ,已經(jīng)不算存在狀態(tài)了
- 以上三種Activity,從上到下優(yōu)先級順序?yàn)?1 ,2,3,在系統(tǒng)內(nèi)存不足情況下,系統(tǒng)回收的優(yōu)先級為3,2,1
- 如果一個(gè)進(jìn)程沒有四大組件,那么它將很快被殺死。所以,一些后臺工作最好放在Service中進(jìn)行,保證進(jìn)程的優(yōu)先級,不會被輕易殺死
5. 切換時(shí)生命周期變換

6. 與Fragment之間生命周期變換
真正的生命周期順序,應(yīng)該在重寫的生命周期方法中的super()之前打印Log,才是真實(shí)的順序,如下:
四、Activity異常銷毀
1. 發(fā)生異常的情況
-
資源相關(guān)系統(tǒng)配置發(fā)生改變導(dǎo)致Activity被殺死并重建
重啟行為旨在通過利用與新設(shè)備配置匹配的備用資源自動(dòng)重新加載您的應(yīng)用,來幫助它適應(yīng)新配置。 - 資源內(nèi)存不足導(dǎo)致優(yōu)先級低的Activity被殺死
2. 發(fā)生異常時(shí)的2個(gè)回調(diào)方法
onSaveInstanceState() 保存狀態(tài)
在Activity異常終止的情況下,才會被調(diào)用,如旋轉(zhuǎn)屏幕配置發(fā)生變更,這個(gè)方法調(diào)用在onStop()之前onRestoreInstanceState() 恢復(fù)狀態(tài)
異常終止后被重新創(chuàng)建會被調(diào)用,調(diào)用在onStart()之后
系統(tǒng)會自動(dòng)幫我們做一些恢復(fù)工作,如Activity的視圖結(jié)構(gòu),其中的文本框輸入內(nèi)容等,因?yàn)閂iew都有以上兩個(gè)方法。
流程:委托思想
Activity異常 > Activity > window > DecorView > 各個(gè)子view,調(diào)用
3. 橫豎屏切換Activity的生命周期
上面提到,資源配置變更導(dǎo)致Activity重啟的原因是:通過利用與新設(shè)備配置匹配的備用資源自動(dòng)重新加載您的應(yīng)用,來幫助它適應(yīng)新配置。
那么,我們同樣可聲明 Activity 自行處理配置變更,這樣可以阻止系統(tǒng)重啟 Activity。如下:
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name">
測試環(huán)境:Android 5.0
1. 未設(shè)置android:configChanges
橫豎屏切換都是,銷毀,重建;onPause > onStop > onDestory > onCreate > onStart > onResume
2. 設(shè)置android:configChanges="orientation"
同上,銷毀,重建
3. 設(shè)置android:configChanges="orientation|keyboardHidden"
同上,銷毀,重建
4. 設(shè)置android:configChanges="orientation|keyboardHidden|screenSize"
或
android:configChanges="orientation|screenSize"
只回調(diào)onConfigurationChanged()方法
小知識:
- 只是想監(jiān)測到橫豎屏的變化只要使用orientation + screenSize兩個(gè)屬性就行了,keyboardHidden是監(jiān)測軟鍵盤變化的
- 因?yàn)?Android 3.2(API 級別 13)開始,當(dāng)設(shè)備在縱向和橫向之間切換時(shí),“屏幕尺寸”也會發(fā)生變化。若要避免由于設(shè)備方向改變而導(dǎo)致運(yùn)行時(shí)重啟,則除了 "orientation" 值以外,您還必須添加 "screenSize" 值
- 有個(gè)說法是切換成豎屏調(diào)用兩次生命周期的,這個(gè)網(wǎng)上有說是2.2版本是這樣,未親測
五、Activity啟動(dòng)模式
1. 4種啟動(dòng)模式
- Standard 默認(rèn)模式
每啟動(dòng)一次Activity,就創(chuàng)建一個(gè)Activity實(shí)例
- SingleTop 棧頂復(fù)用
任務(wù)棧頂有該Activity實(shí)例,回調(diào)onNewIntent(); 棧頂無實(shí)例,創(chuàng)建新實(shí)例
應(yīng)用場景:登錄頁面、接收推送的資訊詳情頁
- SingleTask 棧內(nèi)復(fù)用
該Activity的taskAffity屬性指定的任務(wù)棧,如果不存在,則創(chuàng)建該任務(wù)棧,創(chuàng)建Activity實(shí)例;任務(wù)棧存在,如果棧內(nèi)有該Activity實(shí)例,回調(diào)onNewIntent(),并將任務(wù)棧中在其上面的Activity全部彈出棧; 棧內(nèi)無實(shí)例,創(chuàng)建新Activity實(shí)例
應(yīng)用場景:主頁、瀏覽器打開網(wǎng)頁的Activity(設(shè)置SingleTask,設(shè)置IntentFilter允許隱式啟動(dòng))
正常情況,點(diǎn)擊返回鍵都會返回上一個(gè)Activity,但存在這樣一個(gè)特殊情況:

- SingleInstance 單一實(shí)例
SingleTask的加強(qiáng)版,如果存在該Activity實(shí)例,則回調(diào)onNewIntent();無實(shí)例,則創(chuàng)建新的任務(wù)棧和新的Activity實(shí)例,該實(shí)例是全局的,該任務(wù)棧中也將有且僅有這一個(gè)Activity實(shí)例,通過該Activity啟動(dòng)的其他Activity也將在其他單獨(dú)的任務(wù)棧中創(chuàng)建
應(yīng)用場景:來電提醒、鬧鐘提醒這種全局唯一的頁面,項(xiàng)目中還未用到過
復(fù)用Activity,回調(diào)onNewIntent()的情況:
A為SingleTask,B為Standard,啟動(dòng)順序:A > B > A ,生命周期切換如下
A : onCreate() > onStart() > onResume() > onPause()
B : onCreate() > onStart() > onResume()
A : onStop()
B : onPause()
A : onNewIntent() > onRestart() > onStart() > onResume()
B : onStop() > onDestroy()
2. 設(shè)置啟動(dòng)模式的2種方式
- 清單文件
在清單文件中聲明 Activity 時(shí),您可以使用 <activity> 元素的 launchMode 屬性指定 Activity 應(yīng)該如何與任務(wù)關(guān)聯(lián)。
通過launchMode屬性,指定上述四種啟動(dòng)模式
- Intent 標(biāo)志
啟動(dòng) Activity 時(shí),您可以通過在傳遞給 startActivity() 的 Intent 中加入相應(yīng)的標(biāo)志,
例如: intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
常用Flag:
* **FLAG_ACTIVITY_SINGLE_TOP**
和SingleTop作用相同
* **FLAG_ACTIVITY_CLEAR_TOP**
沒有該Activity實(shí)例的情況下,沒有意義,創(chuàng)建新實(shí)例;
存在該Activity實(shí)例的情況下,和該啟動(dòng)模式有關(guān):
Standard:銷毀任務(wù)棧中已存在的該Activity自身和它之上的所有Activity,重建實(shí)例
SingleTop: 銷毀任務(wù)棧中其上的所有Activity,并回調(diào)onNewIntent()
SingleTask:同上,無意義,和不設(shè)置一樣,回調(diào)onNewIntent(),就是SingTask模式
SingleInstance: 同上,就是SingleInstance模式
* **FLAG_ACTIVITY_NEW_TASK**
旨在找到該Activity屬性taskAffity所指定的任務(wù)棧,創(chuàng)建實(shí)例,默認(rèn)是和包名相同名稱的任務(wù)棧。
**FLAG_ACTIVITY_NEW_TASK不等于 SingleTask**
和要啟動(dòng)的Activity的啟動(dòng)模式有關(guān):
Standard:
不指定taskAffity,在包名任務(wù)棧,始終創(chuàng)建新的實(shí)例;
指定與包名不同任務(wù)棧,不存在的話,創(chuàng)建任務(wù)棧和新的實(shí)例;存在后無反應(yīng),startActivity無效
SingleTop:
不指定taskAffity,在包名任務(wù)棧,始終創(chuàng)建新的實(shí)例;
指定與包名不同任務(wù)棧,不存在的話,創(chuàng)建任務(wù)棧和新的實(shí)例;存在后無反應(yīng),startActivity無效
SingleTask:
在taskAffity指定的任務(wù)棧中,銷毀其上的Activity,回調(diào)onNewIntnet(),不設(shè)置該Flag也一樣,就是Singletask效果
SingleInstance:
在taskAffity指定的任務(wù)棧中,SingleInstance效果,回調(diào)onNewIntent,不設(shè)置該Flag也一樣
**FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP也不等于 SingleTask**
和要啟動(dòng)的Activity的啟動(dòng)模式有關(guān):
Standard:銷毀任務(wù)棧中已存在的該Activity自身和它之上的所有Activity,重建實(shí)例
SingleTop:SingleTask效果,銷毀其上的Activity,回調(diào)onNewIntnet()
SingleTask:singletask效果,銷毀其上的Activity,回調(diào)onNewIntnet(),不設(shè)置該Flag也一樣
SingleInstance:SingleInstance效果,回調(diào)onNewIntent,不設(shè)置該Flag也一樣
以上,測試環(huán)境為Android P
3. taskAffity 和 allowTaskReparenting
taskAffinity表示與 Activity 有著親和關(guān)系的任務(wù)。也就是Activity應(yīng)該存在的任務(wù)棧。屬性取字符串值,該值必須不同于在 <manifest> 元素中聲明的默認(rèn)軟件包名稱,因?yàn)橄到y(tǒng)使用包名稱標(biāo)識應(yīng)用的默認(rèn)任務(wù)關(guān)聯(lián)。
在兩種情況下,關(guān)聯(lián)會起作用:
- 啟動(dòng) Activity 的 Intent 包含 FLAG_ACTIVITY_NEW_TASK 標(biāo)志
將會在taskAffinity所指定的任務(wù)棧中創(chuàng)建Activity。
效果參考上述FLAG_ACTIVITY_NEW_TASK
- allowTaskReparenting = true
該屬性含義是:是否允許 Activity 在與它有著親和關(guān)系的任務(wù)(taskAffity指定)到達(dá)前臺時(shí),轉(zhuǎn)移到那個(gè)任務(wù)。也就是Activity應(yīng)該存在的任務(wù)棧。
試驗(yàn)場景:
A應(yīng)用,B應(yīng)用,B應(yīng)用中的C Activity, C設(shè)置allowTaskReparenting = true
在A中打開C,startActivity 時(shí),設(shè)置FLAG_ACTIVITY_NEW_TASK,如果不設(shè)置沒有轉(zhuǎn)移任務(wù)的效果
結(jié)論:
如果B應(yīng)用任務(wù)棧存在,C直接在B中創(chuàng)建實(shí)例,位于棧頂 ;只要A任務(wù)切換到后臺,再回到前臺,都看不到C了,看到的是C之前的A應(yīng)用中自己的頁面;中間不管是點(diǎn)擊桌面B的laucher按鈕,還是從任務(wù)棧中將B切換到前臺,顯示的都是C
如果B應(yīng)用任務(wù)棧不存在,會創(chuàng)建C的taskAffity所指定的任務(wù)棧,默認(rèn)是B的包名;同樣A切換到后臺再回前臺,只能看到C之前的頁面; 啟動(dòng)B應(yīng)用時(shí),會直接顯示C頁面
六、Intent和IntentFilter
1. Intent的作用
Intent 是一個(gè)消息傳遞對象,您可以使用它從其他應(yīng)用組件請求操作。四大組件中有Activity、Service、BroadcastReceiver需要使用Intent來啟動(dòng)。
2. Intent的分類
-
顯式Intent
Activity的顯式啟動(dòng),就是使用顯式Intent;需要指定目標(biāo)組件名,也是類名;
使用顯式Intent,系統(tǒng)將立即啟動(dòng) Intent 對象中指定的應(yīng)用組件
-
隱式Intent
Activity的隱式啟動(dòng),就是使用隱式Intent;不需要指定類名,需要制定Action,一個(gè)Intent只能有一個(gè)Action;
使用隱式Intent,Android 系統(tǒng)通過將 Intent 的內(nèi)容與在設(shè)備上其他應(yīng)用的清單文件中聲明的 Intent 過濾器進(jìn)行比較,從而找到要啟動(dòng)的相應(yīng)組件,如果多個(gè) Intent 過濾器兼容,則系統(tǒng)會顯示一個(gè)對話框,支持用戶選取要使用的應(yīng)用。
如果沒有找到對應(yīng)的組件,會崩潰,處理方式如下:
// 創(chuàng)建一個(gè)隱式Intent
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");
// 校驗(yàn)系統(tǒng)是否存在對應(yīng)的Activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}
3. IntentFilter是什么
Intent 過濾器是應(yīng)用清單文件中的一個(gè)表達(dá)式,它指定該組件要接收的 Intent 類型。
如果 Activity 聲明 Intent 過濾器,您可以使其他應(yīng)用能夠直接使用某一特定類型的 Intent 啟動(dòng) Activity。同樣,如果您沒有為 Activity 聲明任何 Intent 過濾器,則 Activity 只能通過顯式 Intent 啟動(dòng)。
// 我們最熟悉的過濾器
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
* ACTION_MAIN 操作指示這是主要入口點(diǎn),且不要求輸入任何 Intent 數(shù)據(jù)。
* CATEGORY_LAUNCHER 類別指示此 Activity 的圖標(biāo)應(yīng)放入系統(tǒng)的應(yīng)用啟動(dòng)器。 如果 <activity> 元素未使用 icon 指定圖標(biāo),則系統(tǒng)將使用 <application> 元素中的圖標(biāo)。
特別注意:
為了確保應(yīng)用的安全性,啟動(dòng) Service 時(shí),請始終使用顯式 Intent,且不要為服務(wù)聲明 Intent 過濾器。使用隱式 Intent 啟動(dòng)服務(wù)存在安全隱患,因?yàn)槟鸁o法確定哪些服務(wù)將響應(yīng) Intent,且用戶無法看到哪些服務(wù)已啟動(dòng)。從 Android 5.0(API 級別 21)開始,如果使用隱式 Intent 啟動(dòng)Service,系統(tǒng)會引發(fā)異常(Service Intent must be explicit)。
4. 匹配規(guī)則
- action
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="com.example.action.a" />
...
</intent-filter>
action是一個(gè)字符串,系統(tǒng)預(yù)定了一些,我們也可自定義。
action匹配要求如果IntentFilter中有action,則Intent中必須存在action且必須和IntentFilter中的其中一個(gè)action匹配,另外action字符串區(qū)分大小寫。
- category
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.category.a" />
...
</intent-filter>
category是一個(gè)字符串,系統(tǒng)預(yù)定了一些,我們也可自定義。
category匹配要求Intent中可以沒有category,但intent可以有多個(gè)category,所以如果一旦有category,則Intent的每個(gè)category都必須是IntentFilter中的一個(gè)。
另外startActivity和startActivityForResult都默認(rèn)為Intent增加一個(gè)intent.addCategory(Intent.CATEGORY_DEFAULT);,所以,為了我們的Activity能夠接受隱式調(diào)用時(shí),需要給我們的Activity 的IntentFilter增加這個(gè)Default category
- data
// 合并寫法
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http" android:host="www.baidu.com" ... />
...
</intent-filter>
// 分開寫法
<intent-filter>
<data android:mimeType="video/mpeg" />
<data android:scheme="http"/>
<data android:host="www.baidu.com"/>
...
</intent-filter>
// 都一樣
data由MimeType和Uri構(gòu)成
-
Uri構(gòu)成:
<scheme>://<host>:<port>/<path>例如:http://www.baidu.com:80/a- scheme: Uri模式,如http,file,content等
- host: 主機(jī)名
- port: 端口號
- path: 路徑
線性依賴關(guān)系,scheme未指定,則后面其他參數(shù)無效,
MIME:
媒體類型,由兩部分組成,前面是數(shù)據(jù)的大類別,例如聲音audio、圖象image等,后面定義具體的種類,用來表示不同的文本、圖片、視頻等類型。如:text/plain、image/jpeg
data匹配要求如果IntentFilter中有data,則Intent必須含有data,并且要完全匹配IntentFilter中的其中一項(xiàng)。
IntentFilter中Uri默認(rèn)為content或file,如果未指定Uri,Intent種的scheme部分必須為content或file,才能匹配。
Intent需要設(shè)置Uri和MimeType時(shí),要使用setDataAndType()方法,因?yàn)閱为?dú)調(diào)用setData()和setType(),會互相清除數(shù)據(jù)。
七、任務(wù)和返回棧
任務(wù)是指在執(zhí)行特定作業(yè)時(shí)與用戶交互的一系列 Activity,啟動(dòng)Activity為根Activity,其它為子Activity。 Android系統(tǒng)中所有的 Activity 按照各自的打開順序排列在堆棧(即返回棧)中。 堆棧中的 Activity 永遠(yuǎn)不會重新排列,僅推入和彈出堆棧:由當(dāng)前 Activity 啟動(dòng)時(shí)推入堆棧;用戶使用“返回”按鈕退出時(shí)彈出堆棧。 因此,返回棧以“后進(jìn)先出”對象結(jié)構(gòu)運(yùn)行。

任務(wù)分為前臺任務(wù)(正在與用戶交互的)和后臺任務(wù),后臺可以同時(shí)運(yùn)行多個(gè)任務(wù)。但是,如果用戶同時(shí)運(yùn)行多個(gè)后臺任務(wù),則系統(tǒng)資源緊張時(shí)可能會開始銷毀后臺 Activity,以回收內(nèi)存資源,從而導(dǎo)致 Activity 狀態(tài)丟失

清理返回棧
如果用戶長時(shí)間離開任務(wù),則系統(tǒng)會清除所有 Activity 的任務(wù),根 Activity 除外。 當(dāng)用戶再次返回到任務(wù)時(shí),僅恢復(fù)根 Activity。系統(tǒng)這樣做的原因是,經(jīng)過很長一段時(shí)間后,用戶可能已經(jīng)放棄之前執(zhí)行的操作,返回到任務(wù)是要開始執(zhí)行新的操作。
您可以使用下列幾個(gè) Activity 屬性修改此行為:
- alwaysRetainTaskState
如果在任務(wù)的根 Activity 中將此屬性設(shè)置為 "true",則不會發(fā)生剛才所述的默認(rèn)行為。即使在很長一段時(shí)間后,任務(wù)仍將所有 Activity 保留在其堆棧中。
- clearTaskOnLaunch
如果在任務(wù)的根 Activity 中將此屬性設(shè)置為 "true",則每當(dāng)用戶離開任務(wù)然后返回時(shí),系統(tǒng)都會將堆棧清除到只剩下根 Activity。 換而言之,它與 alwaysRetainTaskState 正好相反。 即使只離開任務(wù)片刻時(shí)間,用戶也始終會返回到任務(wù)的初始狀態(tài)。
- finishOnTaskLaunch
此屬性類似于 clearTaskOnLaunch,但它對單個(gè) Activity 起作用,而非整個(gè)任務(wù)。 此外,它還有可能會導(dǎo)致任何 Activity 停止,包括根 Activity。 設(shè)置為 "true" 時(shí),Activity 仍是任務(wù)的一部分,但是僅限于當(dāng)前會話。如果用戶離開然后返回任務(wù),則任務(wù)將不復(fù)存在。
八、Activity使用小技巧
1. 啟動(dòng)Activity的最佳寫法
A啟動(dòng)B,需要傳遞參數(shù),自己開發(fā)需要每次去看B需要接收哪些參數(shù);分工合作,別人開發(fā)B,你需要問他需要哪些參數(shù),參數(shù)代表什么含義。所以,我們可以在B中定義一個(gè)靜態(tài)方法,如下:
/**
* 啟動(dòng) B Activity
* @param context 源組件
* @param title 標(biāo)題
* @param id id
*/
public static void actionStart(Context context,String title,String id){
Intent intent = new Intent(context,SecondActivity.class);
intent.putExtra("title",title);
intent.putExtra("id",id);
context.startActivity(intent);
}
在A中調(diào)用如下:
SecondActivity.actionStart(this,"啟動(dòng)Activity的最佳寫法","888");
2. 快速退出程序
詳情見百度搜索Activity管理類第一條,思路是:
創(chuàng)建一個(gè)集合,在BaseActivity的onCreate()方法中添加Activity,在onDestroy()中刪除Activity,退出程序時(shí),遍歷集合中所有Activity調(diào)用finish(),將該應(yīng)用的所有Activity銷毀
3. Activity的Dialog樣式
<activity android:name=".Activity.FirstActivity"
android:theme="@android:style/Theme.Dialog"/>
或
// 繼承AppCompatActivity時(shí)使用
<activity android:name=".Activity.FirstActivity"
android:theme="@style/Theme.AppCompat.Dialog"/>
4. Activity轉(zhuǎn)場動(dòng)畫
通過重寫overridePendingTransition(int enterAnim, int exitAnim)實(shí)現(xiàn)的。
參數(shù):
- enterAnim,將要打開的Activity的進(jìn)入動(dòng)畫id
- exitAnim,將要退出的Activity的退出動(dòng)畫id
這個(gè)方法在startActivity(Intent)或finish()之后會被立即調(diào)用。
動(dòng)畫使用補(bǔ)間動(dòng)畫,在res/anim下創(chuàng)建動(dòng)畫文件,需要以 <alpha> <scale> <translate> <rotate> <set>為根節(jié)點(diǎn)。
下面我們以MainActivity打開SecondActivity示例:
left_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="2000"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="2000" />
</set>
right_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="2000"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="2000" />
</set>
MainActivity使用
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.right_in,R.anim.left_out);
left_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%p" android:toXDelta="0" android:duration="2000"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="2000" />
</set>
right_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="100%p" android:duration="2000"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="2000" />
</set>
SecondActivity使用
@Override
public void onBackPressed() {
// 這里會調(diào)用finish
super.onBackPressed();
overridePendingTransition(R.anim.left_in,R.anim.right_out);
}
如上,即可實(shí)現(xiàn)在打開和退出SecondActivity時(shí)有動(dòng)畫效果,不過,要是每個(gè)Activity都這樣寫會很麻煩,所以,升級版如下:
value/styles.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<!--這個(gè)屬性會對Activity切換動(dòng)畫有影響,如果動(dòng)畫失效,請檢查是否有該屬性-->
<!--<item name="android:windowIsTranslucent">true</item>-->
<!-- 設(shè)置activity切換動(dòng)畫 -->
<item name="android:windowAnimationStyle">@style/ActivityAnim</item>
</style>
<!--設(shè)置Activity切換動(dòng)畫樣式-->
<style name="ActivityAnim" parent="@android:style/Animation">
<item name="android:activityOpenEnterAnimation">@anim/right_in</item>
<item name="android:activityOpenExitAnimation">@anim/left_out</item>
<item name="android:activityCloseEnterAnimation">@anim/left_in</item>
<item name="android:activityCloseExitAnimation">@anim/right_out</item>
</style>
</resources>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myandroiddemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"> <!--應(yīng)用主題-->
</manifest>
以上,通過設(shè)置一個(gè)Activity切換樣式,然后設(shè)置給我們應(yīng)用的主題,最后應(yīng)用主題,這樣我們的應(yīng)用就會有Activity切換效果了,而不需要每個(gè)Activity都去調(diào)用overridePendingTransition方法了。
個(gè)人總結(jié),水平有限,如果有錯(cuò)誤,希望大家能給留言指正!如果對您有所幫助,可以幫忙點(diǎn)個(gè)贊!如果轉(zhuǎn)載,希望可以留言告知并在顯著位置保留草帽團(tuán)長的署名和標(biāo)明文章出處!最后,非常感謝您的閱讀!