【Android开发日记】之入门篇(十一)——Android的Intent机制

继续咱们的Android之路吧。今天我要介绍的是Android的Intent。html

对于基于组件的应用开发而言,不只须要构造和寻找符合需求的组件,更重要的是要将组件有机的链接起来,互联互通交换信息,才可以最终提供应用所指望的服务。而为了可以更好地实现组件复用,充分地利用每个组件的能力,就须要这些组件链接的模式足够灵活和统一,而且能够进行动态地扩展。因此Android提供了利用Intent对象创建链接并实现组件通讯的模式。Intent对象是Android组件链接的核心,集中体现了整个组件链接模型的设计思想。android

 

1、Intent对象算法

Android的Intent机制最核心的设计思想,就是引入了组件管理服务做为链接组件的管理者。该服务能够经过组件的配置信息了解系统中每一个组件的类别和功能,从而帮助调用组件寻找符合其需求的实现组件,将调用者与实现者完全解耦。缓存

通常的Intent实现的流程图:
数据结构

 

  1. Intent对象的构成
    Intent对象的这些做用,都是经过它的实现和设计体现出来的。从数据结构来看,Intent类的实现很是简单,它并无包含复杂的逻辑功能,只是包含着若干个数据项。
    (1)Action项 在Intent中用来表示动做,能够经过Intent的setAction和getAction来进行操做。在Android中定义了不少标准的动做,好比:Intent.ACTION_VIEW等。这些动做约定了    Android组件间的通讯规范,保证了组件系统的可扩展性。
    (2)Data项,当发起请求时,调用组件若是有明确的数据对象,一般就会用Data项来存储表示。Data数据也是用字符串进行存储,它的格式符合URI标准。因此能够经过URI来描述数据来加强数据的做用范围。
    (3)Type项, Type是MINE格式的字符串数据,用于描述组件可以处理的请求类型,或者补充说明Data数据的类型,它能够经过通配符*来表示整个类别的信息。注意:Data项和Type项在不少时候是互斥使用的,当调用Intent.setType时,以前设定的Data信息就会被清空,反之亦然。但能够经过intent.setDataAndType()来同时设置。
    (4)Category项 Category表示约束。每一个Intent对象可包含多个categroy项。而一个组件须要支持所有的Category才可能处理请求。如一个组件须要启动其余应用,且但愿进入的是这个应用的入口组件,这时就须要添加Intent.CATEGORY_LAUNCHER做为约束。
    (5)Component项  它指的是目标组件的类型信息,能够经过Intent.setComponent方法利用类名进行设置,也能够经过Intent.setClass方法利用类型对象信息进行设置。
    (6)Extras项 Intent中数据传输的载体,负责将数据从调用组件传递到实现组件。
    (7)Flags项 Flags是一个整数型,由一系列的标志位聚集而成。
    在组件开发中,应该遵循SDK或第三方拟定的相关规范。当一个组件须要支持特定的Action时,就须要同支持相关的Extras项和Data项相关内容。协议的完整性和正确性是整个Android Intent机制的根基。
  2. Intent对象的解析
    从实现组件的选择来看,Intent对象能够分为两类:精确描述的Intent和模糊描述的Intent。
    (1)精确描述的Intent,指的是全部带有Component信息的Intent对象,调用组件能够经过Intent.setComponent或Intent.setClass等方法进行设置。当组件管理服务收到Intent对象时,会先校验其Component数据项,若是含有Component信息,组件管理服务只须要依照Component构造对应的实现组件。平时咱们用的Intent的跳转都是用的精确Intent.
    (2)除此以外,全部不包含Component信息的Intent对象,都归类于模糊描述的Intent.

2、Intent Filter对象
除了Intent对象,在Android的Intent机制中还有一个重要的角色:Intent Filter对象。Intent Filter对象,指的是android.content.IntentFilter类的对象,它是Intent对象的“姊妹对象”。与Intent对象相似,Intent Filter对象也包含Action、Type、Data、Catagory等数据项,每一个数据项的结构和含义,与Intent的数据项也一一对应。app

  1. Intent Filter的用途
    Intent Filter是各个组件用于描述其功能的,经过组件的Intent Filter信息,Android的组件管理应用就能够了解和掌握各个组件所具有的能力和可以处理的请求。当组件管理服务接收到调用组件发送来的基于模糊描述的Intent对象时,会与全部组件的Intent Filter信息进行匹配计算,寻找符合需求的实现组件。
    每一个组件均可以有任意数量的Intent Filter。组件包含的Intent Filter对象越多,说明他能接受Intent请求范围越广,同时,其实现也会越复杂。
  2. Intent Filter的范例
             <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>

 3、Intent 匹配算法ide

当组件管理服务接受到请求组件的Intent对象后,会先查看Intent对象是否包含了目标实现组件的Component信息。若是不包括,则会从应用管理服务中获取全部组件的Intent Filter信息,并与Intent对象相比较,选择符合需求的实现组件。其中涉及到的就是Intent的匹配算法了。
函数

算法输入的是进行比较的Intent对象和Intent Filter对象;若是返回值为正,则表示匹配成功,而且,正值越大意味着匹配程度越高,流程图以下。post


其中,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:xxx@oo.com"));
                startActivity(intent);

开始匹配检查。ACTION包含OK—>data包含OK—>Category检查(经过Context.startActivity函数发出请求,组件管理服务会自动为其添加上Intent.CATEGORY_DEFAULT)OK—>匹配成功

 

4、匹配组件的选择

若是有多个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的调用时,可直接返回上次记录的结果,从而跳过匹配的过程,加速组件的调用。

5、Intent使用的一个小例子

  1. 一个ActivityDemo工程,用以启动其余应用的Activity。其中的代码为

    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);
                }
            });
    
        }
    
    }

     

  2. 另外一个应用,即包名为com.example.demo的应用,其中配置文件部分为:

    <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>
  3. 安装以上两个应用,运行效果图:

    点击精确Intent,成功跳转到另外一个应用中。
    点击模糊Intent,出现组件选择列表,以下图:

PS:其中关于PackageManager的详细用法,能够参考这篇文章Android随笔—PackageManager详解

6、结束语

看到这里,你们是否是对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机制/