继续我们的Android之路吧。今天我要介绍的是Android的Intent。
对于基于组件的应用开发而言,不仅需要构造和寻找符合需求的组件,更重要的是要将组件有机的连接起来,互联互通交换信息,才能够最终提供应用所期望的服务。而为了能够更好地实现组件复用,充分地利用每一个组件的能力,就需要这些组件连接的模式足够灵活和统一,并且可以进行动态地扩展。所以Android提供了利用Intent对象建立连接并实现组件通信的模式。Intent对象是Android组件连接的核心,集中体现了整个组件连接模型的设计思想。
一、Intent对象
Android的Intent机制最核心的设计思想,就是引入了组件管理服务作为连接组件的管理者。该服务可以通过组件的配置信息了解系统中每个组件的类别和功能,从而帮助调用组件寻找符合其需求的实现组件,将调用者与实现者彻底解耦。
二、Intent Filter对象
除了Intent对象,在Android的Intent机制中还有一个重要的角色:Intent Filter对象。Intent Filter对象,指的是android.content.IntentFilter类的对象,它是Intent对象的“姊妹对象”。与Intent对象类似,Intent Filter对象也包含Action、Type、Data、Catagory等数据项,每个数据项的结构和含义,与Intent的数据项也一一对应。
<activity android:name="com.example.activitydemo.SecondActivity"> <intent-filter android:icon="" android:label="" android:priority=""> <action android:name=""></action> <category android:name=""></category> <data android:host="" android:mimeType="" android:path="" android:pathPattern="" android:port="" android:scheme=""/> <!-- 可以继续添加相关的actio、category和data项 --> </intent-filter><!-- 可以继续添加相关的intent-filter项 --> </activity>
三、Intent 匹配算法
当组件管理服务接受到请求组件的Intent对象后,会先查看Intent对象是否包含了目标实现组件的Component信息。如果不包括,则会从应用管理服务中获取所有组件的Intent Filter信息,并与Intent对象相比较,选择符合需求的实现组件。其中涉及到的就是Intent的匹配算法了。
算法输入的是进行比较的Intent对象和Intent Filter对象;如果返回值为正,则表示匹配成功,并且,正值越大意味着匹配程度越高,流程图如下。
其中,Data与Type信息是Intent Filter中最复杂的数据项,其比较算法是决定Intent与Intent Filter对象匹配程度的关键。
如果Intent的对象包含Type信息,就必须要求Intent Filter的Type信息与之对应,否则,匹配也将以失败告终;然后,如果Intent对象中含有Data项,则会将该Data项的URI信息拆分为Scheme和Authority等部分,逐一与Intent Filter对象中对应的部分进行比较,只要两者有任何不符的地方,匹配都会失败。
以Android原生的邮件应用为例,它配置了如下的Intent Filter信息:
<activity android:name=".SecondActivity.MessageCompose"> <intent-filter > <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.SENDTO" /> <data android:scheme="mailto"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <!-- 可以继续添加相关的actio、category和data项 --> </intent-filter> <!-- 可以继续添加相关的intent-filter项 --> </activity>
当调用者发出如下请求时,就会触发一次意图匹配:
Intent intent = new Intent(Intent.ACTION_SENDTO); intent.putExtra(Intent.EXTRA_TEXT, ""); //其中,mailto这部分是URI的scheme部分 intent.setData(Uri.parse("mailto:[email protected]")); startActivity(intent);
开始匹配检查。ACTION包含OK—>data包含OK—>Category检查(通过Context.startActivity函数发出请求,组件管理服务会自动为其添加上Intent.CATEGORY_DEFAULT)OK—>匹配成功。
四、匹配组件的选择
如果有多个Intent Filter对象与调用组件发出的Intent对象都相匹配,就需要在所有符合条件的Intent Filter对象中进行筛选,选出最符合调用组件和用户需求的实现组件,这就是匹配组件的选择。而我们可以设定Intent Filter对象的优先级来进行设定,即通过<intent-filter>配置项中的android:priority属性进行变更,或者通过IntentFilter.setPriority函数进行动态地修改。范围是-1000至1000,默认为0。
在Android的Intent机制中,通过引入第三方组件管理服务,降低了调用组件与实现组件之间的耦合,提高了整个系统的灵活性及组件的复用性,使得应用开发变得更为简单快捷。但同时,正是由于第三方服务地介入增加了组件间连接的成本,可能会使组件间的调用不够流畅。因此,在组件管理服务中,系统对组件的匹配和选择过程进行了大量的优化,以提高组件调用的效率,其中包括:
(1)索引
组件管理服务通过哈希表,为所有Intent Filter对象的Action、Type等数据项建立索引。每个索引项对应着一组Action相同,Type相同或者其他数据项相同的Intent Filter对象。Intent先与索引项比较,快速地选择出可能与Intent相匹配的Intent Filter对象。这样,就加快了匹配速度。
(2)缓存
所谓缓存,是将Intent与Intent Filter的匹配结果记录下来,当再碰到相同Intent的调用时,可直接返回上次记录的结果,从而跳过匹配的过程,加速组件的调用。
五、Intent使用的一个小例子
public class ChangeActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = (Button) findViewById(R.id.button); Button button2 = (Button) findViewById(R.id.button2); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); //因为是精确启动,这些不加都是没问题的 //intent.addCategory(Intent.CATEGORY_LAUNCHER); // intent.setAction(Intent.ACTION_MAIN); ComponentName cn = new ComponentName( "com.example.demo",//另一个应用的包名 "com.example.demo.MainActivity");//要启动的另一个应用的类名 //intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setComponent(cn); Log.d("TEST", intent.toString()); startActivity(intent); //精确启动的另一种方法 /*Intent LaunchIntent = getPackageManager() .getLaunchIntentForPackage("com.example.demo"); Log.d("TEST", LaunchIntent.toString()); startActivity(LaunchIntent);*/ } }); button2.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //只能获得系统级的应用组件 //action为MAIN,应用入口界面 Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); startActivity(intent); //获取所有符合的组件,包括第三方安装的应用 //List<ResolveInfo> activities = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); //自定义对话框 //ShowSelectActivityDialog(activities); } }); } }
<activity android:name="com.example.demo.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
PS:其中关于PackageManager的详细用法,可以参考这篇文章Android随笔—PackageManager详解
六、结束语
看到这里,大家是不是对Intent的传递原理有所了解了呢。形象一点地说,Intent好比是插头,而Intent Filter就好比是插座,插座的孔只要满足插头的孔脚数量就能工作了,多了没事,但少了就不行。
Intent是Android应用模型的核心,解决了组件间的连接问题。通过组件管理服务提供的Intent匹配策略,降低了组件间的耦合度,提高了平台的灵活性,增强了组件的复用性,从根本上减轻了应用开发的负担。
参考文章:(1) android Intent机制详解 http://www.oschina.net/question/565065_67909
(2)android intent和intent action大全 http://www.apkbus.com/android-72361-1-1.html
========================================
作者:cpacm
地址:http://www.cpacm.net/2015/03/26/Android开发日记(八)——Android的Intent机制/