Android Intent隐式启动通过scheme打开应用

本文转载自tickTick的BLOG,原始出处
本文通过完成一个实战任务,来掌握Android开发中隐式Intent的用法。
任务:假设我们已经实现了一个视频播放器(PlayerActivity),我们希望能把它注册到系统中,当用户点击本地视频或者在线视频时,能启动这个视频播放器。
(假设该类的全路径为:com.jhuster.videoplayer.PlayerActivity)
1. 什么是隐式Intent?
Intent是Android中比较重要的组件,常用来启动一个新的Activity或者Service、广播某个事件,以及在Android组件之间传递数据。通过Intent来启动新的Activity或者Service通常有两种方法,一种是显示启动,另一种是隐式启动。
显示启动就是在明确指出要启动的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);

隐式启动则是不明确指定启动哪个Activity或者Service,而是通过设置Action、Data、Category,让系统来筛选出合适的目标。
例如拨打电话:

Intent intent =new Intent(Intent.ACTION_DIAL,Uri.parse(“tel:021-80961111”));
startActivity(intent);

系统接收到隐式启动请求后,会根据系统中各个Activity在AndroidManifest.xml文件中声明的<intent-filter>来比较和判断是否匹配当前的Intent请求的。
因此,如果我们希望PlayerActivity能够被系统隐式启动,则首先需要在AndroidManifest.xml文件中为该Activity添加<intent-filter>.
2. 为PlayerActivity添加<intent-filter>
<intent-filter>的标签有很多,这里只介绍和添加最基本且最常用的三个标签,分别是<action>,<category>和<data>。
2.1 添加<action>
这个标签是必须添加的,可以自己定义,也可以使用系统预定义的变量,Android系统默认定义了很多action,具体可以查看SDK文档,或者Google一下“android.intent.action.”。
这里,因为我们的类是用来“播放视频”的,因此可以使用系统预定义的:android.intent.action.VIEW,它表示需要启动某个Activity显示指定的数据(包括图片、视频、文档等)。
添加了后的如下所示:

<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可以设置一个或者多个category标签。常用的一般有3个:DEFAULT,HOME,LAUNCHER

DEFAULT  默认动作
HOME     设置为本地桌面应用
LAUNCHER 本APP的启动Activity

本应用中我们使用DEFAULT类别即可,DEFAULT也是category最常用的选项。
添加了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 代表数据源,是<intent-filter>中最复杂的标签,因为不同的Activity支持的数据来源和类型多种多样,所以需要通过详细的data标签信息来指明。

data 标签有很多属性,包括:
android:host: 指定主机名,例如:google.com
android:port:  制定主机端口,例如: 80
android:path:  指定URL的有效路径值,例如: /index/examples
android:mimeType: 指定组件可以执行的数据类型,例如:image/jpeg,video/*
android:scheme: 指定特定的模式,例如:content,http

这里,假设我们的视频播放器支持多种数据来源,包括:本地视频文件,本地媒体URL,网络视频流(HTTP、RTMP、RTSP协议),另外,假设我们的视频播放器只支持mp4和3gpp两种文件格式。
那么,下面我们来添加两种最常用<data>的标签,scheme和mimeType,并且解释每条标签对应的是怎样的一种数据来源或者数据格式。
(1)<data android:scheme="xxx"/>
这里的xxx可以是:file,content,网络协议(HTTP,RTMP、RTSP等)
本应用中我们给PlayerActivity的中<Intent-filter>添加:

<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:scheme="http"/>
<data android:scheme="rtsp"/>

添加了这样几条data标签项之后,如果隐式Intent中的数据来源URL是以“file://”、“content://”、“http://”、“rtsp://”开头的URL资源,都会隐式地启动我们的PlayerActivity。
例如,其他的Activity可以通过下面的方法来隐式启动我们的PlayerActivity.

Intent intent =new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.fromFile(new File("/sdcard/test.3gp")));
startActivity(intent);

Uri.fromFile这条语句会把指定的文件位置转换为以“file://”开头的Uri对象,如上述例子最终得到的URL为:“file:///sdcard/test.3gp”
同理,可以通过Uri.parse来转换我们常见的网络地址字符串为Uri对象,例如:

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用来设置数据类型,例如图像数据(image/png或者image/),视频数据(video/mp4或者video/),如果使用*代表匹配所有的子类型。
MIME TYPE是互联网的一种标记数据类型的标准,现在已经支持非常多的类型了,这里我不一一列举,大家可以在Google上搜索一下。
本应用中我们假设需要支持的是mp4和3gpp两种类型,那么,我们可以添加这样两条 mimeType :

<data android:mimeType="video/3gpp"/>
<data android:mimeType="video/mp4"/>

那么,其他的Activity就可以通过下面的方法来隐式启动我们的PlayerActivity. 注意,当<intent-filter>已经添加了mimeType之后,隐式Intent必须设置Type参数才能匹配到该Activity,所以建议使用setDataAndType方法,而不是单一的setData方法。

Intent intent =new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File("/sdcard/test.3gp")),"video/3gpp");
startActivity(intent);

当然,这里的"video/3gpp"也可以写成:"video/*",但这样可能会匹配到一些不支持3gpp的播放器。

(3) 小结
添加了<data>标签后的如下所示:

<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中获取参数
通过上面的介绍,我们已经知道了怎样添加<intent-filter>以及怎样通过隐式Intent来调用我们的PlayerActivity,那么,下面我们还要了解如何在PlayerActivity中解析来自隐式Intent的参数。
其实,Intent提供了很多方法可以Get相关的参数信息,例如:

public String getAction();
public Uri    getData();
public String getScheme();
public String getType();

上述方法分别可以获取Intent的Action,Data Uri,Scheme和MimeType值。
对于“file://”开头的Uri对象,我们可以通过Uri.getPath方法得到去除了“file://”前缀的具体文件地址。例如: “file:///sdcard/test.mp4”则可以转换为实际的“/sdcard/test.mp4”。
对于网络码流,例如:“http://”、“rtsp://”等开头的Uri,则可以直接通过toString()方法转换为实际地址的字符串。
而对于“content://”开头的URI对象,一般是从系统的媒体数据库中检索出来的结果,因此需要反向查找得到实际的文件地址,这里提供一个函数进行转换。

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. 总结
到这里算是把隐式Intent的重要知识点都讲清楚了,本文转载自tickTick的BLOG,原始出处。谢谢。
请务必保留此出处http://ticktick.blog.51cto.com/823160/1621957

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容