Android开发实践:实战演练隐式Intent的用法

本文通过完成一个实战任务,来掌握Android开发中隐式Intent的用法。

任务:假设我们已经实现了一个视频播放器(PlayerActivity),我们希望能把它注册到系统中,当用户点击本地视频或者在线视频时,能启动这个视频播放器。

(假设该类的全路径为:com.jhuster.videoplayer.PlayerActivity)

[注]:本文完整的示例代码请到我的Github下载,地址:VideoPlayer

1. 什么是隐式Intent?

Intent是Android中比较重要的组件,常用来启动一个新的Activity或者Service、广播某个事件,以及在Android组件之间传递数据。通过Intent来启动新的Activity或者Service通常有两种方法,一种是显示启动,另一种是隐式启动。

显示启动就是在明确指出要启动的Activity或者Service的类或者包名。例如:

Intent intent = newIntent(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显示指定的数据(包括图片、视频、文档等)。

添加了<action>后的<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>如下所示:

<activityandroid:name="com.jhuster.videoplayer.PlayerActivity">
    <intent-filter>
        <actionandroid: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>标签后的<intent-filter>如下所示:

<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()) {
            int column_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的重要知识点都讲清楚了,本文的示例代码请到我的Github下载(地址在本文开头)有不清楚或者错误的地方,欢迎大家留言讨论或者来信[email protected]交流。另外转载请著名本文作者和出处(ticktick),谢谢。

时间: 2024-08-08 00:06:17

Android开发实践:实战演练隐式Intent的用法的相关文章

Android成长之路(7)——关于隐式Intent的用法

Android其中最重要的特性之一,就是一个应用可以基于"action"来切换到另一个应用.比如,你的应用想要查找地方,在地图上显示.但是不一定要创建一个activity来显示地图,可以使用Intent发起一个请求来查看地址,然后Android系统会启动一个可以显示地图的应用. 之前,会使用到显式的Intent来让一个activity跳转到另一个activity.但是,当想要跳转到一个独立的应用时,比如查看地图,这时候就一定要使用隐式Intent. 创建一个隐式Intent 隐式Int

Android中显示和隐式Intent的使用

显示启动activity                                                                                                                   这个很简单,下面是代码示例:为了看着方便,所以就把layout直接截图了,里面的代码只是一些简单的布局.activity_login.xml: activity_main.xml: 下面是Manifest.xml中的代码 1 <?xml vers

Android中的显示Intent和隐式Intent

1.显示Intent 在onclick方法中 Intent intent=new Intent(FirstActivity.this,SecondActivity.class); startActivity(intent); 2.隐式Intent 隐式Intent不明确指出我们要启动哪一个活动,而是指定一系列更为抽象的action和category等信息,然后交由系统去分析这个intent,并帮我们找到合适的Intent去启动 通过标签下配置的内容,指定当前活动能够响应的action和categ

Android开发学习笔记:浅谈显示Intent和隐式Intent

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://liangruijun.blog.51cto.com/3061169/655132 Intent寻找目标组件的两种方式: 显式Intent:通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的. 隐式Intent:通过Intent Filter来实现的,它一般用在没有明确指出目标组件名称的前提下,一般是用于在不同应用程序之间.

Android开发:显式/隐式Intent意图跳转Activity总结

显式跳转 在已知包名和类名的情况下常用的跳转方法: 是 nt mIntent = new Intent(); mIn Int etent.setClassName("com.android.settings","com.android.settings.Settings"); mContext.startActivity(mIntent); 我们也常这么用: y.class); startActivity(intent); 这是跳转到当前应用的某个Activity,

隐式Intent的使用——Android学习笔记3

隐式Intent的使用 一.为什么要用隐式Intent? 但如果想调用别的程序的组件时,且开发人员往往并不清楚别的应用程序的组件名称,这时我们只能用隐式Intent,隐式Intent恰恰相反,它不会用组件名称定义需要激活的目标组件,而是Android系统帮助应用程序寻找与Intent请求意图最匹配的组件. 二.Android系统怎么找? 主要是通过Intent Filter来寻找与隐式Intent相关的对象.具体的选择方法是:Android将Intent的请求内容<intent-filter>

在Android中Intent的概念及应用(一)——显示Intent和隐式Intent

Intent寻找目标组件的两种方式: 显式Intent:通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的. 隐式Intent:通过Intent Filter来实现的,它一般用在没有明确指出目标组件名称的前提下,一般是用于在不同应用程序之间. 一.显示Intent: 创建一个Activity的完整过程: 1.手动创建一个类,让其继承自Activity: public class MyAty extends Activity 2.让其绑定一个

android隐式intent使用场景解析

Android 隐式intent相信大家都有用过,大部分场景我们用显式intent已经能满足我们的业务需求,隐式intent大部分都是用来启动系统自带的Activity或Service之类的组件.昨天有个业务场景就是,我在第三方依赖库 module A里面有个Activity A,现在需要在Activity A里面启动 module app里面的Activity B,我想了一下,可以用隐式intent来实现这个功能,而且实现代码最简洁,不用修改或添加其他代码. 隐式intent很简单,首先要在A

隐式Intent找不到Activity:android.content.ActivityNotFoundException

Here is what i encountered: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=me.waye.intentdemo.intent.action.WAYE_ACTION cat=[me.waye.intentdemo.intent.category.WAYE_CATEGORY] } 在学习隐式启动Activity的时候遇到这个错误,用的书是李刚的疯狂An