本文轉(zhuǎn)載自tickTick的BLOG扭勉,原始出處。
本文通過完成一個(gè)實(shí)戰(zhàn)任務(wù)偏形,來掌握Android開發(fā)中隱式Intent的用法刁岸。
任務(wù):假設(shè)我們已經(jīng)實(shí)現(xiàn)了一個(gè)視頻播放器(PlayerActivity)耘子,我們希望能把它注冊(cè)到系統(tǒng)中果漾,當(dāng)用戶點(diǎn)擊本地視頻或者在線視頻時(shí),能啟動(dòng)這個(gè)視頻播放器谷誓。
(假設(shè)該類的全路徑為:com.jhuster.videoplayer.PlayerActivity)
1. 什么是隱式Intent?
Intent是Android中比較重要的組件吨凑,常用來啟動(dòng)一個(gè)新的Activity或者Service捍歪、廣播某個(gè)事件户辱,以及在Android組件之間傳遞數(shù)據(jù)。通過Intent來啟動(dòng)新的Activity或者Service通常有兩種方法糙臼,一種是顯示啟動(dòng)庐镐,另一種是隱式啟動(dòng)。
顯示啟動(dòng)就是在明確指出要啟動(dòng)的Activity或者Service的類或者包名变逃。例如:
Intent intent = new Intent(this, PlayerActivity.class);
startActivity(intent);
Intent intent =new Intent();
intent.setClass(this,PlayerActivity.class);
startActivity(intent);
Intent intent =new Intent();
intent.setClassName(“com.jhuster.videoplayer”,“com.jhuster.videoplayer.PlayerActivity”);
startActivity(intent);
隱式啟動(dòng)則是不明確指定啟動(dòng)哪個(gè)Activity或者Service必逆,而是通過設(shè)置Action、Data揽乱、Category名眉,讓系統(tǒng)來篩選出合適的目標(biāo)。
例如撥打電話:
Intent intent =new Intent(Intent.ACTION_DIAL,Uri.parse(“tel:021-80961111”));
startActivity(intent);
系統(tǒng)接收到隱式啟動(dòng)請(qǐng)求后凰棉,會(huì)根據(jù)系統(tǒng)中各個(gè)Activity在AndroidManifest.xml文件中聲明的<intent-filter>來比較和判斷是否匹配當(dāng)前的Intent請(qǐng)求的损拢。
因此,如果我們希望PlayerActivity能夠被系統(tǒng)隱式啟動(dòng)撒犀,則首先需要在AndroidManifest.xml文件中為該Activity添加<intent-filter>.
2. 為PlayerActivity添加<intent-filter>
<intent-filter>的標(biāo)簽有很多福压,這里只介紹和添加最基本且最常用的三個(gè)標(biāo)簽,分別是<action>或舞,<category>和<data>荆姆。
2.1 添加<action>
這個(gè)標(biāo)簽是必須添加的,可以自己定義映凳,也可以使用系統(tǒng)預(yù)定義的變量胞枕,Android系統(tǒng)默認(rèn)定義了很多action,具體可以查看SDK文檔魏宽,或者Google一下“android.intent.action.”腐泻。
這里,因?yàn)槲覀兊念愂怯脕怼安シ乓曨l”的队询,因此可以使用系統(tǒng)預(yù)定義的:android.intent.action.VIEW派桩,它表示需要啟動(dòng)某個(gè)Activity顯示指定的數(shù)據(jù)(包括圖片、視頻蚌斩、文檔等)铆惑。
添加了后的如下所示:
<activity android:name="com.jhuster.videoplayer.PlayerActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
</intent-filter>
</activity>
2.2 添加<category>
category代表類別,定義了Activity的類別送膳,Activity可以設(shè)置一個(gè)或者多個(gè)category標(biāo)簽员魏。常用的一般有3個(gè):DEFAULT,HOME叠聋,LAUNCHER
DEFAULT 默認(rèn)動(dòng)作
HOME 設(shè)置為本地桌面應(yīng)用
LAUNCHER 本APP的啟動(dòng)Activity
本應(yīng)用中我們使用DEFAULT類別即可撕阎,DEFAULT也是category最常用的選項(xiàng)。
添加了category后的如下所示:
<activity android:name="com.jhuster.videoplayer.PlayerActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
2.3 添加<data>
data 代表數(shù)據(jù)源碌补,是<intent-filter>中最復(fù)雜的標(biāo)簽虏束,因?yàn)椴煌腁ctivity支持的數(shù)據(jù)來源和類型多種多樣棉饶,所以需要通過詳細(xì)的data標(biāo)簽信息來指明。
data 標(biāo)簽有很多屬性镇匀,包括:
android:host: 指定主機(jī)名照藻,例如:google.com
android:port: 制定主機(jī)端口,例如: 80
android:path: 指定URL的有效路徑值汗侵,例如: /index/examples
android:mimeType: 指定組件可以執(zhí)行的數(shù)據(jù)類型幸缕,例如:image/jpeg,video/*
android:scheme: 指定特定的模式晰韵,例如:content发乔,http
這里,假設(shè)我們的視頻播放器支持多種數(shù)據(jù)來源宫屠,包括:本地視頻文件列疗,本地媒體URL,網(wǎng)絡(luò)視頻流(HTTP浪蹂、RTMP抵栈、RTSP協(xié)議),另外坤次,假設(shè)我們的視頻播放器只支持mp4和3gpp兩種文件格式古劲。
那么,下面我們來添加兩種最常用<data>的標(biāo)簽缰猴,scheme和mimeType产艾,并且解釋每條標(biāo)簽對(duì)應(yīng)的是怎樣的一種數(shù)據(jù)來源或者數(shù)據(jù)格式。
(1)<data android:scheme="xxx"/>
這里的xxx可以是:file滑绒,content闷堡,網(wǎng)絡(luò)協(xié)議(HTTP,RTMP疑故、RTSP等)
本應(yīng)用中我們給PlayerActivity的中<Intent-filter>添加:
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:scheme="http"/>
<data android:scheme="rtsp"/>
添加了這樣幾條data標(biāo)簽項(xiàng)之后杠览,如果隱式Intent中的數(shù)據(jù)來源URL是以“file://”、“content://”纵势、“http://”踱阿、“rtsp://”開頭的URL資源,都會(huì)隱式地啟動(dòng)我們的PlayerActivity钦铁。
例如软舌,其他的Activity可以通過下面的方法來隱式啟動(dòng)我們的PlayerActivity.
Intent intent =new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.fromFile(new File("/sdcard/test.3gp")));
startActivity(intent);
Uri.fromFile這條語(yǔ)句會(huì)把指定的文件位置轉(zhuǎn)換為以“file://”開頭的Uri對(duì)象,如上述例子最終得到的URL為:“file:///sdcard/test.3gp”
同理牛曹,可以通過Uri.parse來轉(zhuǎn)換我們常見的網(wǎng)絡(luò)地址字符串為Uri對(duì)象佛点,例如:
Intent intent =new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://ticktick.blog.51cto.com/test.mp4"));
startActivity(intent);
(2)<data android:mimeType="xxx"/>
mimeType用來設(shè)置數(shù)據(jù)類型,例如圖像數(shù)據(jù)(image/png或者image/)躏仇,視頻數(shù)據(jù)(video/mp4或者video/)恋脚,如果使用*代表匹配所有的子類型腺办。
MIME TYPE是互聯(lián)網(wǎng)的一種標(biāo)記數(shù)據(jù)類型的標(biāo)準(zhǔn)焰手,現(xiàn)在已經(jīng)支持非常多的類型了糟描,這里我不一一列舉,大家可以在Google上搜索一下书妻。
本應(yīng)用中我們假設(shè)需要支持的是mp4和3gpp兩種類型船响,那么,我們可以添加這樣兩條 mimeType :
<data android:mimeType="video/3gpp"/>
<data android:mimeType="video/mp4"/>
那么躲履,其他的Activity就可以通過下面的方法來隱式啟動(dòng)我們的PlayerActivity. 注意见间,當(dāng)<intent-filter>已經(jīng)添加了mimeType之后,隱式Intent必須設(shè)置Type參數(shù)才能匹配到該Activity工猜,所以建議使用setDataAndType方法米诉,而不是單一的setData方法。
Intent intent =new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File("/sdcard/test.3gp")),"video/3gpp");
startActivity(intent);
當(dāng)然篷帅,這里的"video/3gpp"也可以寫成:"video/*"史侣,但這樣可能會(huì)匹配到一些不支持3gpp的播放器。
(3) 小結(jié)
添加了<data>標(biāo)簽后的如下所示:
<activity android:name="com.jhuster.videoplayer.PlayerActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:scheme="http"/>
<data android:scheme="rtsp"/>
<data android:scheme="rtmp"/>
<data android:mimeType="video/3gpp"/>
<data android:mimeType="video/mp4"/>
</intent-filter>
</activity>
3. 在PlayerActivity中獲取參數(shù)
通過上面的介紹魏身,我們已經(jīng)知道了怎樣添加<intent-filter>以及怎樣通過隱式Intent來調(diào)用我們的PlayerActivity惊橱,那么,下面我們還要了解如何在PlayerActivity中解析來自隱式Intent的參數(shù)箭昵。
其實(shí)税朴,Intent提供了很多方法可以Get相關(guān)的參數(shù)信息,例如:
public String getAction();
public Uri getData();
public String getScheme();
public String getType();
上述方法分別可以獲取Intent的Action家制,Data Uri正林,Scheme和MimeType值。
對(duì)于“file://”開頭的Uri對(duì)象颤殴,我們可以通過Uri.getPath方法得到去除了“file://”前綴的具體文件地址觅廓。例如: “file:///sdcard/test.mp4”則可以轉(zhuǎn)換為實(shí)際的“/sdcard/test.mp4”。
對(duì)于網(wǎng)絡(luò)碼流诅病,例如:“http://”哪亿、“rtsp://”等開頭的Uri,則可以直接通過toString()方法轉(zhuǎn)換為實(shí)際地址的字符串贤笆。
而對(duì)于“content://”開頭的URI對(duì)象蝇棉,一般是從系統(tǒng)的媒體數(shù)據(jù)庫(kù)中檢索出來的結(jié)果,因此需要反向查找得到實(shí)際的文件地址芥永,這里提供一個(gè)函數(shù)進(jìn)行轉(zhuǎn)換篡殷。
public static String getVideoPath(Context context, Uri uri) {
Uri videopathURI = uri;
if(uri.getScheme().toString().compareTo("content") ==0) {
Cursor cursor = context.getContentResolver().query(uri,null,null,null,null);
if(cursor.moveToFirst()) {
intcolumn_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
videopathURI = Uri.parse(cursor.getString(column_index));
return videopathURI.getPath();
}
}else if(uri.getScheme().compareTo("file") ==0) {
return videopathURI.getPath();
}
return videopathURI.toString();
}
4. 總結(jié)
到這里算是把隱式Intent的重要知識(shí)點(diǎn)都講清楚了,本文轉(zhuǎn)載自tickTick的BLOG埋涧,原始出處板辽。謝謝奇瘦。
請(qǐng)務(wù)必保留此出處http://ticktick.blog.51cto.com/823160/1621957