转载请注明出处:http://blog.csdn.net/zhouli_csdn/article/details/45696591
意图和意图过滤器
意图是一个消息对象你可以从其它组件中发出一个请求动作,通常有三种用法:
* 启动一个activity
* 通过startActivity(intent),intent可以携带数据。
* 如果希望在activity结束时接收一个结果,startActivityForResult,你可以在activity的onActivityResult(int requestCode,int resultCode,Intent data).
* 启动service
* 传递Intent,startService。
* 传递Intent,bindService。
* 发出广播
一个广播消息任何应用程序都可以接收。系统为一些系统事件提供广播,例如开机,设备开始充电。
* sendBroadcast
* sendOrderedBroadcast
* sendStickyBroadcast
意图类型
显示意图
显示意图指定了要启动的组件的名称(类全称)。你可以在自己使用它,因为你知道它的名称。
隐示意图
它不声明具体的组件名称,但是你需要声明一个动作(action),允许其它应用的组件处理它。
当你启动一个显示意图,系统立即根据intent里面指定的组件启动它。
当你使用隐示意图,系统会根据其它应用manifest中的意图过滤器进行匹配。如果匹配到一个意图过滤器,系统将会把intent传递给它并启动。如果有多个匹配,系统会显示一个对话框让用户选择。
一个意图过滤器是你在manifest中为组件指定的希望接受的intent类型。如果你不为一个activity指定任何意图,那他只能被显示意图启动。
注意:确保你的应用是安全的,使用显示意图启动service,并且不为service声明任何意图过滤器。使用隐式意图有安全风险,因为你不确定到底是什么service相应了意图,用户也看不见什么service启动了。
Android5.0(Api 21),如果你使用隐式意图bindService,会抛出异常。
创建一个意图
组件名称
如果有名称,那就是显示意图;如果没有指定名称,会根据intent的内容决定(action,data,category,etc.)
setComponent()、setClass()、setClassName()、构造器。
action
action很大程度上决定了intent其它部分(例如data、extras)的结构
你可以自己指定actions,但是你通常应该使用Intent类内部定义的或者其它类定义的。例如:
ACTION_VIEW:当你有一些东西可以通过activity要展示给用户。(例如:图片、地图的地址)
ACTION_SEND:也被成为分享意图,当你有一些东西可以通过其它app分享。
Intent还有很多actions,其他类Settings有actions可以打开系统设置的某一个页面。
setAction()或者构造器指定action
自定义action,要带上包名:static final String ACTION_TIMETRAVEL = “com.example.action.TIMETRAVEL”;
data
一个Uri对象。数据类型通常由action决定。例如:ACTION_EDIT,那么data应该包含编辑数据的uri。
当创建意图,指定data的MIME类型很重要。例如一个播放音频的不能播放视频即使uri格式相似。有时候,MIME类型可以从 URI 得到例如:content:URI ,暗示数据是contentprovider类型。
只需要设置data uri,使用setData(),只需要设置MIME类型,使用setType()。
注意:如果你需要设置data和type,使用setDataAndType()。如果分别调用setData和setType,它们会相互消除另一个的设置
category
包含了应该处理这个Intent的组件的种类的字符串。一个Intent可以包含任意多的category。
CATEGORY_BROWSABLE:目标activity可以使用浏览器打开一个连接
CATEGORY_LAUNCHER:一个任务的初始化activity,被展现在应用的launcher列表中。
更多请查看Intent类
使用addCategory()
以上三个属性使Intent的核心。通过它们,系统就可以确定应该启动哪个应用组件。下面的属性不会影响:
extras
使用putExtra()添加键值对、还可以使用putExtras添加Bundle。
Intent类有很多标准数据类型
flags
可以指定系统如何加载一个activity。(例如activity应该属于哪一个task),加载后如何对待(例如是否属于最近的活动列表)查看setFlags().
显示意图举例
// Executed in an Activity, so 'this' is the Context // The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse(fileUrl)); startService(downloadIntent);
隐式意图举例
注意:如果系统中没有可以匹配隐式意图的组件,调用会失败并且应用会崩溃。可以使用resolveActivity()检测
// Create the text message with a string Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType(HTTP.PLAIN_TEXT_TYPE); // "text/plain" MIME type // Verify that the intent will resolve to an activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(sendIntent); }
注意:这次,没有使用URI,因为intent的数据类型已经指定extras携带内容。
迫使使用选择对话框
如果用户设置了默认程序,用户可能希望不同场景使用不同的app(Intent.createChooser):
Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show the chooser dialog Intent chooser = Intent.createChooser(sendIntent, title); // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
接收隐式意图
一个应用组件应该为它能做的每一个任务分开定义intent filters。例如一个activity可以显示图片也可以编辑图片,那就定义两个filters。当activity启动后,可以根据intent里面的内容决定是否展示图片编辑器。使用intent-filter标签,你可以在它里面多次使用action、data、category。
* action:通过它的name属性定义动作的名称,应该使用动作的文字字符串而不是类的常量。
* data:指定接收数据的类型。可以使用多个URI属性(scheme、host、port、path、etc.),MIME类型。
* category:通过它的name属性定义动作的名称,应该使用动作的文字字符串而不是类的常量。
* 注意:如果要接收隐式意图,必须提供category的CATEGORY_DEFAULT值。
<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>
Filters举例:
<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>
ACTION_MAIN:指定这是主入口
CATEGORY_LAUNCHER:这个activity的图标必须展示在launcher中,如果activity没有,使用application的。
这两个必须一起使用使app可以展现在launcher中。
注意:The MIME type, application/vnd.google.panorama360+jpg, is a special data type that specifies panoramic photos, which you can handle with the Google panorama APIs.
使用PendingIntent
PendingIntent是Intent的一个包装。PendingIntent的主要目的是为了允许其它应用就像在你自己应用的进程中使用包含的intent。
主要的PendingIntent使用场景:
* 声明一个意图,当用户在通知栏执行一个动作(系统的NotificationManager执行这个intent)
* 声明一个意图,当用户在你的AppWidget执行动作(系统的HomeScreen执行这个intent)
* 声明一个意图,在将来的一个指定的时间执行(系统的AlarmManger执行)
* 创建PendingIntent:
* PendingIntent.getActivity() 启动一个activity
* PendingIntent.getService() 启动一个service
* PendingIntent.getBroadcast() 启动一个广播
* 每一个方法有两个参数,当前app的context和要包含的intent。可以指定标志intent如何使用(例如intent可以被使用多次)
Resolve Intent
当系统接到一个启动activity隐式意图的时候,会在系统中通过比较一下三个属性查找匹配的:
* intent action
* intent data(both URI and data type)
* intent category
ActionTest
条件
Intent
Filter
Result
Action
1
>=1
Intent必须比配其中一个action
Action
1
0
fail
Action
0
>=1
pass
CategoryTest
条件
Intent
Filter
Result
Category
>=1
>=1
Intent中所有的category必须与filter中的匹配
Category
0
>=1
pass
注意:系统自动的为隐式Intent添加了CATEGORY_DEFAULT,所以activity如果想接收隐式Intent,必须包含CATEGORY_DEFAULT。
DataTest
URI匹配:(1表示有;0表示没有,.表示不确定)
条件
Intent
Filter
Result
scheme/authority/path
1/./.
1/0/0
Intent只需要包含scheme
scheme/authority/path
1/1/.
1/1/0
需要匹配scheme和authority
scheme/authority/path
1/1/1
1/1/1
三者匹配才pass
Data匹配:
条件
Intent
Filter
Result
URI/MIME type
0/0
0/0
pass
URI/MIME type
1/0
1/0
只有URI匹配,才pass
URI/MIME type
0/1
0/1
MIME type相同,才pass
URI/MIME type
1/1
1/1
两者匹配/Intent有一个包含contnet:或者file:的URI而且filter没有URI
最后一个条件暗示组件的data如果只有MIME type,那么将默认支持content:和file:,所以组件可以只包含MIME type,例如:
<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
包含URI和MIME type的例子,例如下面的支持组件从网络获得一个video:
<intent-filter> <data android:scheme="http" android:type="video/*" /> ... </intent-filter>
意图匹配
意图匹配不只是用来启动一个组件,还可以用来查看设备上组件的一些设定。
例如:Launcher通过查找包含ACTION_MAIN 和CATEGORY_LAUNCHER的intent filter来确定app。
你自己的应用也可以这样做。
PackageManager有一些查询方法,queryIntentActivities(),queryIntentServices(),queryBroadcastReceivers(),
还有一些resolve…()方法决定最好的相应组件。