啟動 Activity 分為兩種,顯式調用和隐式調用。顯式調用需要明确指出被啟動元件的包名類名。隐式調用需要 Intent 能夠比對目标元件的 IntentFilter 中所設定的過濾資訊,如果不比對将無法啟動目标 Activity
一、IntentFilter 簡介
- 意圖過濾器的意思
- manifest檔案中activity标簽的子标簽。
- IntentFilter 的過濾資訊(子标簽)有 action、category、data
1、IntentFilter 注意點
1、一個activity下可能有多個intentfilter,一個intent隻要能比對任何一組intentFilter下的資訊便可成功啟動activity。
2、一個intentFilter中action 、category、data都可以有多個。
3、想要隐式開啟activity 必須在intentFilter添加 <category android:name=“android.intent.category.DEFAULT” />
二、Action規則
1、系統定義了一些Action字元串
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
2、我們也可以自定義Action字元串
<activity android:name=".ActivityC">
<intent-filter>
<action android:name="com.example.test" />//添加自定義字元串即可
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
3、Action比對規則
1、intentFilter中的action可以有很多,隻要intent添加的action和intentFilter中其中一個action比對即可
2、action區分大小寫,大小寫不同的字元串是不同的action。
3、intentFilter 至少要有一個action
4、栗子
Intent intent = new Intent();
intent.setAction("com.example.test"); //intent 添加action。比對intent-filter 下的一個action即可成功打開activity
startActivity(intent);
<activity android:name=".ActivityC">
<intent-filter>
<action android:name="com.example.test" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
三、Category規則
1、比對規則
1、intentFilter中的category可以有很多,隻要intent設定的category和intentFilter的比對即可。
2、系統在調用startActivity或者startActivityForResult時,會預設為intent加上了android.intent.category.DEFAULT這個category。是以為了activity能夠接受隐式調用必須在intentFilter下設定android.intent.category.DEFAULT。
2、栗子
mainactivity開啟main2Activity。
#MainActivity
#main2activity的配置
#點選按鈕(直接崩潰 如下)
找不到activity?我明明添加了action還和intentFilter下的其中一個action比對,并且我添加了category也比對了。這是為啥???還記得我們之前說過得系統在調用startActivity或者startActivityForResult時,預設為intent加上了android.intent.category.DEFAULT這個categor是以要想隐式開啟activity這個categrory必須添加待intent-filter中。
Intent intent = new Intent();
intent.setAction("com.example.test1");
intent.addCategory(Intent.CATEGORY_DEFAULT); // 實際還有這個 系統封裝在startActivity中了
intent.addCategory("com.example.category2");
startActivity(intent);
四、 data比對規則
1、data簡介
data由兩部分組成mimeType和URI,文法如下。
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string"/>
2、mimeType
1、媒體類型,如image/jpeg 、audio/mpeng4-generic、vodeo/* 可以表示圖檔文本視屏等不同媒體格式。
2、data 中可以不指定這個屬性。
3、URI結構
1、scheme:URI的模式,比如http,file,content等字元串,此屬性不可省略。
2、Host:URI的主機名比如 “www.baidu.com” ,此屬性不可省略。
3、Port:URI中的端口号,比如80此屬性可省略
4、parth ,pathPattern,pathPrefix 這三個參數表示路徑資訊。此屬性可省略
4、栗子
<activity android:name=".SecActivity">
<!-- action 、category、data-->
<intent-filter>
<action android:name="aaa" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="secactivity"
android:scheme="test" />
</intent-filter>
</activity>
val intent = Intent()
intent.action = "aaa"
//這裡可以不寫CATEGORY_DEFAULT
// intent.addCategory(Intent.CATEGORY_DEFAULT) 系統在startActivity時會預設加上
intent.data = Uri.parse("test://secactivity")
startActivity(intent)
5、tips
1、URI是有預設值的。URI預設值為content或file。
2、如果需要為intent指定完整的data需要調用intent.setDataAndType(uri,type);這個方法,
3、setData 設定data的uri,setType 設定data的miniType但是 setData setType這兩個方法彼此會清除對方值。(參考兩個方法源碼)
這樣比對規則就總結完了,另外注意intentFilter的比對規則對Service,broadcastReceiver同樣适用,不過系統對于Service的建議盡量使用顯示意圖來啟動服務。
當元件設定了intent filter後便可支援隐式開啟,這時exported屬性預設會為true,元件支援外部應用開啟。無intent filtre時元件的exported預設為false。
五、activity相關的常用方法
1、onNewIntent 觸發條件有哪些?
1、activity 設定為SingleTop 且位于棧頂:再次開啟activity會走 onNewIntent
2、activity設定為SingleTask、singleinstance任務棧中存在執行個體:再次開啟activity會走onNewIntent
2、resolveActivity
避免找不到隐式activity而crash。注意參數PackageManager.MATH_DEFAULT_ONLY的使用。
if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
startActivity(intent);
} else {
Toast.makeText(this, "Activity Not Found", Toast.LENGTH_SHORT).show();
}
4、異常狀态下的資料恢複
onSaveInstanceState()
onRestoreInstanceState()
#思想:委托思想
首先 Activity 被意外終止時,Activity 會調用 onSaveInstanceState 去儲存資料,然後 Activity 會委托 Window 去儲存資料,接着 Window 在委托它上面的頂級容器再去一一通知它的子元素來儲存資料,這樣整個資料儲存過程就完成了。
5、startActivityForResult使用
#mainActivity
...
...
Intent intent = new Intent(this, SecondActivity.class);
startActivityForResult(intent, 0x01);
...
...
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0x01 && resultCode == 0x02
&& data != null) {
// todo
}
}
#secondActivity
Intent intent = new Intent();
intent.putExtra("name", "i am second");
setResult(0x02, intent);
finish();