定義:Intent是一個消息傳送對象,可以用它來訪問另外一個組件
可以用于以下三個場景:
- startActivity
startActivity()
startActivityForResult()
- startService
Android 5.0以上可以使用JobScheduler啟動
所有版本可以使用:
startService();
bindService();
- sendBroadcast
三種調用方法
sendBroadCast()
sendOrderedBroadCast()
sendStickyBroadcast()
Intent 類型
- 顯示類型
直接指定調用組件的名字,一般用于自己的APP內部 - 隱式類型
沒有指定組件的名字,而是聲明一般的action行為,用此方法可以允許調用另外一個APP的組件
啟動Service最好使用顯示Intent,否則會存在安全風險,因為無法確定service什么時候被調用,而service又是用戶感知不到的組件
Android 5.0開始,如果bindService()隱式調用啟動service,會拋出異常
Intent的創建
一個Intent對象包含了Android系統應該啟動哪個組件的信息
一個Intent可以包含以下信息:
-
componentName
指定需要啟動組件的名字
此項是可選的,用來區分顯示Intent和隱式Intent。
賦值的方法有以下幾種- Intent的構造方法
- setComponent()
- setClass()
- setClassName
-
action
指定Intent要完成的動作,為字符串常量
action可自定義,也可使用系統的,一般自定義的話最好加上自己APP的包名前綴
一些系統標準的Action常量
ACTION_VIEW,startActivity(),喚起系統相冊
ACTION_SEND,startActivity(),把一些數據發送給另外的一些APP,如email,社交軟件等
ACTION_CALL,startActivity(),喚起打電話界面
不定期補充...
除了Intent定義了Action常量,其他的類也有定義,比如Settings,可以用來跳轉到系統指定的設置界面
action賦值的方法有一下幾種:- Intent的構造方法
- setAction()
data
根據給定的Uri尋找匹配的目標組件,如果不給定MIME類型,會進行推導,給定MIME類型,則強制使用此類型。
不同的Action有對應的data數據指定。
其中data的值設置為setData(),MIME的設置為setType()
常用值如下所示:
tel://: 號碼數據格式,后跟電話號碼。
mailto://: 郵件數據格式,后跟郵件收件人地址。
smsto://: 短息數據格式,后跟短信接收號碼。
content://: 內容數據格式,后跟需要讀取的內容。
file://: 文件數據格式,后跟文件路徑。
geo:// latitude, longitude:經緯數據格式,在地圖上顯示經緯度所指定的位置。
Uri指定數據指向那種數據格式,MIME指定數據具體的類型。比如Image和Audio有同樣的Uri,但是MIME的類型是不同的。
setData()和setType()會互相覆蓋,所以當需要同時設置Uri和MIME時,為了避免這種情況,可以調用setDataAndType()
- category
執行Action的附加信息。可以放置很多category,但是大多數intent是不需要category的
常用值如下:
CATEGORY_DEFAULT:Android系統中默認的執行方式,按照普通Activity的執行方式執行。
CATEGORY_HOME:設置該組件為Home Activity。
CATEGORY_PREFERENCE:設置該組件為Preference。
CATEGORY_LAUNCHER:設置該組件為在當前應用程序啟動器中優先級最高的Activity,通常為入口ACTION_MAIN配合使用。
CATEGORY_BROWSABLE:設置該組件可以使用瀏覽器啟動。
CATEGORY_GADGET:設置該組件可以內嵌到另外的Activity中。
通過addCategory()指定 - extras
用來存放需要傳遞的數據,以鍵值對的形式進行存儲和訪問
通過putExtras()方法設置 - flags
設置Activity的啟動模式,例如:
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_NO_HISTORY
FLAG_ACTIVITY_SINGLE_TOP
具體的筆記放到Activity上
通過setFlags()方法設置
顯示Intent的例子
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);
隱式Intent的例子
其中resolveActivity()用來判斷Intent是否能夠被解析,防止APP崩潰
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");
//Intent chooser = Intent.createChooser(sendIntent, title);//強制使用選擇器
//if (sendIntent.resolveActivity(getPackageManager()) != null) {
// startActivity(chooser);
//}
// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}
接收一個隱式Intent
需要在manifest文件中配置<intent-filter>,<intent-filter>包含如下三個子項:
<action>
<data>
<category>
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
MIME類型 application/vnd.google.panorama360+jpg為指定的全景照片數據類型
<activity android:name="MainActivity">
<!-- This activity is the main entry, should appear in app launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="ShareActivity">
<!-- This activity handles "SEND" actions with text data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/vnd.google.panorama360+jpg"/>
<data android:mimeType="image/*"/>
<data android:mimeType="video/*"/>
</intent-filter>
</activity>
使用PendingIntent
PendingIntent是對Intent的包裝,使外部的APP能夠像在內部APP那樣對所包含的Intent進行使用
主要有如下的使用場景:
- Notification
- App Widget
- AlarmManager
取得實例的方法如下:
PendingIntent.getActivity(),啟動Activity
PendingIntent.getService(),啟動Service
PendingIntent.getBroadcast(),啟動BroadcastReceiver
狀態欄通知:
int icon = android.R.drawable.my_icon;
long when = System.currentTimeMillis();//通知發生的時間為系統當前時間
Notification notification = new Notification(icon, null, when);//新建一個通知,第一個參數為圖標,第二個參數為短暫提示標題,第三個為通知時間
notification.defaults = Notification.DEFAULT_SOUND;//發出默認聲音
notification.flags |= Notification.FLAG_AUTO_CANCEL;//點擊通知后自動清除通知
Intent openintent = new Intent(this, OtherActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, openintent, 0);//當點擊消息時就會向系統發送openintent意圖
notification.setLatestEventInfo(this, "標題", "內容", contentIntent);//setLatestEventInfo表示設置點擊該通知的事件
int notifyCode = 0;
//獲取通知管理器
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(notifyCode , notification);//第一個參數為自定義的通知唯一標識
action匹配規則
如果intent-filter設置了action的過濾規則,比如下面的XML代碼,
<intent-filter>
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
...
</intent-filter>
那么:
- intent不設置action,則直接不通過
- intent設置了多個Action,則只要有一個匹配上,則可以通過
//不通過
Intent intent = new Intent();
//通過
intent.setAction("android.intent.action.EDIT");
//通過
intent.setAction("android.intent.action.EDIT");
intent.setAction("android.intent.action.test");
Category匹配規則
如果intent-filter設置了category的過濾規則,如下面的XML代碼,
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
...
</intent-filter>
那么:
- Intent不設置category,則都通過,不論intent-filter設置多少category
- intent設置了category,intent上的category能夠匹配上intent-filter設置的category,才能夠通過
比如:
//通過
Intent intent = new Intent();
//通過
intent.addCategory("android.intent.category.DEFAULT"),可以匹配上
//通過
intent.addCategory("android.intent.category.BROWSABLE")
//不通過
intent.addCategory("android.intent.category.DEFAULT")
intent.addCategory("android.intent.category.test")
Data匹配規則
intent-filter中的<data>結構由Uri和MIME Type組成
Uri包括如下幾部分:
scheme:整個Uri的模式,如http,ftp,content等
如果scheme未指定,則忽略host
如果只指定scheme,則所有和intent-filter相同的scheme都匹配host:Uri的域名,如www.google.com
如果host未指定,則忽略portport:Uri的端口
path:包含的路徑信息,如:folder/subfolder/etc
如果scheme,host都未指定,則忽略path
整體組成:<scheme>://<host>:<port>/<path>,如 content://com.example.project:200/folder/subfolder/etc
MIME Type:表示image/ipeg,video/*等媒體類型
匹配規則如下:
intent中的data必須和intent-filter完全匹配才能通過。有如下幾種情況:
a.intent沒有設置Uri和MIME Type,同時intent-filter也沒有設置
b.intent只包含Uri,但未包含MIME Type,同時能夠匹配上intent-filter設置的Uri,并且intent-filter為設置MIME Type
c.intent只設置MIME Type,同時intent-filter也設置了相同的MIME Type并且未指定Uri
d.intent設置了Uri和MIME Type,intent-filter只設置了MIME Type,則intent的Uri的scheme必須為content:或是file:。即,intent-filter如果沒有設置Uri,只設置了MIME Type,則Uri為content:或file:的模式。也就是說,過濾的規則希望組件能夠從文件(file)或內容提供者(content provider)獲取到本地數據。
規則d例子,從相冊獲取圖片:
<intent-filter>
<data android:mimeType="image/*" />
...
</intent-filter>
則intent的匹配規則為:
Intent intent = new Intent();
intent.setDataAndType(Uri.parse("file://test"), "image/*");
startActivity(intent);
如果intent-filter設置了多個data,則intent中的data只要和其中一個匹配就可以通過
為了防止APP崩潰,所有的intent匹配規則進行調用前都要進行判斷處理:
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
本知識點完~