购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

6.3 一个Intent的基本组成与配置

Android系统会根据Intent来启动某个组件。显示意图明确启动的组件,但是对于隐式意图而言,到底这个Intent会启动哪个组件,取决于Intent中各项属性的设置。下面将详细介绍Intent的各项属性,以及它们的使用与配置。

Intent对象中,封装了六个重要的属性:Component、Action、Data、Category、Extra和Flag。Intent就是依靠这六个属性携带信息,从而确定以什么方式启动那个组件并传递对应数据,需要注意的是,通常这六个属性中,需要几个属性配合使用,而非单独使用,Intent也对这些属性提供了对应的getter、setter方法。下面分别对这六个属性进行详细的讲解。

6.3.1 Component Name

Intent在内部封装了一个ComponentName类型的对象,它用于明确指定待启动的组件。对于Intent而言,ComponentName是一个可选属性,当通过它明确的指定了需要启动的组件后,Intent就是一个显示意图。也就是说,它所开启的组件必须是当前应用包下的,而当不指定ComponentName属性时,Intent将是一个隐式意图。

ComponentName提供了多个构造方法,这些方法如下:

· ComponentName(String pkg,String cls)

· ComponentName(Context pkg,String cls)

· ComponentName(Context pkg,Class<?> cls)

从ComponentName提供的几个构造方法中可以看出,它需要指定一个包名和一个类名,这样就可以唯一的确定一个组件了。

示例:通过ComponentName来明确启动一个组件。

代码清单:\codes\06\03\IntentComponentNameDemo\src\com\bookdemo\intentcomponentnamedemo\MainActivity.java

btnCompomentName.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        // 实例化一个ComponentName对象,指定开启的组件
        ComponentName componentName = new ComponentName(
        MainActivity.this, Activity.class);
        Intent intent = new Intent();
        // 为Intent指定Component
        intent.setComponent(componentName);
        // 根据Intent对象开启一个Activity
        startActivity(intent);
    }
}); 

新开启的页面,显示出开启组件的包名与类名。

代码清单:\codes\06\03\IntentComponentNameDemo\src\com\bookdemo\intentcomponentnamedemo\Activity2.java

public class Activity2 extends Activity {
    private TextView tvShow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_page);
        tvShow = (TextView) findViewById(R.id.tvShow);
        // 从Intent中获取其中的ComponentName对象
        ComponentName componentName = getIntent().getComponent();
        // 在TextView上输出包名和类名
        tvShow.setText("组件包名为:" + componentName.getPackageName() + "\n"
                + "组件类名:" + componentName.getClassName());
    }
}

如果只使用ComponentName属性来通过显式意图来开启一个组件,那么在清单文件AndroidManifest.xml中,可以使用最简便的方式,为需要开启的属性设置android:name属性即可,无需额外配置<intent-filter…/>元素。

代码清单:AndroidManifest.xml

<activity android:name="com.bookdemo.intentcomponentnamedemo.Activity2" >

在模拟器上运行效果如图所示:

为了简化步骤,Intent提供了构造方法,去设置ComponentName属性,所以通常并不显式的去实例化ComponentName对象。

对于上面的示例,可以直接使用Intent的构造方法来指定ComponentName。

代码清单:MainActivity.java

btnIntent.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        Intent intent=new Intent(MainActivity.this, Activity2.class);
        startActivity(intent);
    }
});

使用Intent的构造方法来简化ComponentName的实例化过程,和直接实例化ComponentName再对Intent进行设置效果是一样的。其实在Intent的构造方法中,同样也是实例化了一个ComponentName对象,这一点通过查看Intent的源码即可看出来。

Android源码中,Intent的一个构造方法:

public Intent(Context packageContext, Class<?> cls) {
    mComponent = new ComponentName(packageContext, cls);
}

通常情况下,对于一些不希望外部应用程序启动并访问的组件,可以不为其设置<intent-filter…>元素而是设置意图过滤器,这样在应用中就可以通过指定ComponentName来指定唯一一个组件来启动。一般而言,对于一个Service,就应该使用ComponentName属性来指定一个显式意图,用来开启Service组件。

6.3.2 Action

Action属性是一个String类型,它指定了当前Intent的作用,通常配合Category属性一起使用。

Action属性一般用于设置隐式意图,它指定了当前Intent需要做什么,是查看内容,还是选择数据。当设置了Action属性之后,系统会根据意图过滤器来过滤符合的组件进行启动。所以Action需要使用<intent-filter…/>元素,并通过<action…/>元素对其进行设置。

为Intent指定Action有两种方式,一种是使用Intent的几个与Action相关的构造方法,在初始化Intent的设置Action属性,另外一种方式就是使用Intent.setAction(String)方法为Intent指定Action属性。值得注意的是,在同一个Intent中,只能为其指定一个Action属性。

除了在清单文件AndroidManifest.xml中,通过<action…/>元素自定义的一些Action以外,Intent还为我们提供了一些标准的Action,这些Action属性值通过静态常量的形式定义在Intent中。这里介绍一些常用的:

· ACTION_MAIN:应用程序的入口。

· ACTION_VIEW:显示指定数据。

· ACTION_EDIT:编辑指定数据。

· ACTION_PICK:从组件中选择某些数据并返回。

· ACTION_DIAL:打开拨号面板。

· ACTION_CALL:直接向指定号码拨打电话。

· ACTION_SEND:发送消息。

· ACTION_ANSWER:应答电话。

· ACTION_INSERT:插入数据。

· ACTION_DELETE:删除数据。

6.3.3 Category

Category属性需要配合Action属性设置一个隐式意图,Action指定了Intent需要做什么,而Category对这个Action进行了分类。比如Action指定需要查看的内容,而Category指定了如何查看内容。

Category属性和Action一样,也是String类型,它同样需要在<intent-filter…/>元素中,通过<category…/>元素对其进行配置。

为Intent指定Category属性可以使用addCategroy()方法,Category属性不同于Action属性,在同一个Intent中,可以指定多个Category属性。

与Action属性一样,除了我们在清单文件AndroidManifest.xml中,通过<category…/>元素自定义的一些Category属性以外,Intent还提供了一些标准的Category属性值,它们被以静态常量的形式定义,方便我们使用,这里介绍一些常用的Intent定义的Category属性:

· CATEGORY_DEFAULT:默认的Category,配置的时候必须要配置这个Category。

· CATEGORY_BROWSABLE:指定Activity能被浏览器安全调用。

· CATEGORY_TAB:指定Action作为TabActivity的Tab页。

· CATEGORY_LAUNCHER:指定Activity为程序的启动页。

· CATEGORY_HOME:指定Activity为系统桌面。

下面通过一个示例程序,演示如何通过指定Action和Category这两个属性,设置一个隐式的意图,开启Activity。

代码清单:\06\03\IntentActionDemo\src\com\bookdemo\intentactiondemo\MainActivity.java

@Override
    public void onClick(View v) {
        Intent intent = new Intent();
        switch (v.getId()) {
        case R.id.btnImplicit1:
            // 指定Action和Category
            intent.setAction("com.bookdemo.intentactiondemo.MyAction");
            intent.addCategory("com.bookdemo.intentactiondemo.OneCategory");
            // 判断系统中是否存在此Intent
            if (intent.resolveActivity(getPackageManager()) != null) {
                startActivity(intent);
            }
            break;
        case R.id.btnImplicit2:
            intent.setAction("com.bookdemo.intentactiondemo.MyAction");
            intent.addCategory("com.bookdemo.intentactiondemo.TwoCategory");
            if (intent.resolveActivity(getPackageManager()) != null) {
                startActivity(intent);
            }
            break;
        case R.id.btnImplicit3:
            intent.setAction("com.bookdemo.intentactiondemo.MyAction");    
            //如果存在多个匹配的组件,增加一个选择框
            Intent choose=Intent.createChooser(intent, "请选择一个Activity");
            if (choose.resolveActivity(getPackageManager()) != null) {
                startActivity(choose);
            }
            break;
        default:
            break;
        }
    }

在清单文件中配置这两个Activity,并配置对应的过滤器。

代码清单:\06\03\IntentActionDemo\AndroidManifest.xml

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="com.bookdemo.intentactiondemo.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>
    <activity android:name="com.bookdemo.intentactiondemo.OneActivity" >
        <intent-filter>
        <action android:name="com.bookdemo.intentactiondemo.MyAction" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="com.bookdemo.intentactiondemo.OneCategory" />
        </intent-filter>
    </activity>
    <activity android:name="com.bookdemo.intentactiondemo.TwoActivity" >
        <intent-filter>
        <action android:name="com.bookdemo.intentactiondemo.MyAction" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="com.bookdemo.intentactiondemo.TwoCategory" />
        </intent-filter>
    </activity>
</application>

这两个新增的Activity,实现的效果是一样的,在屏幕上打印Intent中Action与Category的值,这里给出OneActivity的代码,TwoActivity的与它类似。

代码清单:\06\03\IntentActionDemo\src\com\bookdemo\intentactiondemo\OneActivity.java

public class OneActivity extends Activity {
    private TextView tvShow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_page);

        tvShow = (TextView) findViewById(R.id.tvShow);
        // 得到当前Intent对象
        Intent intent = getIntent();

        // 获得Intent的Action属性值
        String action = intent.getAction();
        String category = "";
        // 获取Category属性值
        Set<String> set = intent.getCategories();
        if (set != null) {
            Object[] objs = getIntent().getCategories().toArray();

            if (objs.length > 0) {
                category = (String) objs[0];
            }
        }
        tvShow.setText("这是Activity1 \n action:" + action + "\n" + "categroy:"
                + category);
    }
}

在模拟器上运行,分别点击开启Activity1和开启Activity2按钮,它们都可以通过Action属性和Category属性唯一匹配一个Activity,效果如下:

选择待开启的Activity按钮的响应事件中,仅设置了Action属性,没有设置Category属性。而通过这个Action,Android系统将会在意图过滤器中,找到两个匹配的Activity。这时,将弹出一个对话框,列出意图过滤器匹配出的符合的Activity,供用户选择。效果如下:

6.3.4 Data

Data属性接受一个Uri类型的对象,通常用于向Action属性指定的行为提供其所需要的数据。

一个标准的Uri,可以决定传递的是何种类型的数据,又可以指定具体的数据值。所以一般而言Uri属性可以简单分为两个部分:数据类型部分和数据部分。例如:tel:13333333333,它可以被拆分成两个部分。

· tel:前缀,用于指定该数据的类型是一个电话号码。

· 13333333333:数据,表明了操作的电话号码。

在创建一个Intent的时候,通常还需要指定其MIME类型,通常使用type属性设置,用于指定Data属性所指定数据的类型。例如:存在一个Activity,它可以指定一个图片文件进行显示,但是无法播放一个音频文件,因为它们都需要指定一个文件,通常使用"file://"为前缀的Url来指定文件的路径,通过设置MIME类型来直接Intent接受的数据类型,可以帮助Android系统找到最匹配的组件来响应这个Intent。

Data属性在清单文件AndroidManifest.xml中,可以在<intent-filter…/>元素之中增加<data…/>元素配置。通常在其中设置android:scheme属性,用于指定Uri的前缀,如果需要设置MIME类型,还需要通过android:mimeType属性进行设置。

为Intent单独设置Data和MIME类型可以分别使用setData()以及setType()。如果在Intent中需要同时用到这两个属性,还可以使用setDataAndType()方法同时设置Data和MIME类型。

6.3.5 Extra

Extra属性,是一个Bundle的类型的对象。可以传递一个Key-Value的键值对,在开启组件的时候,携带一些数据到新开启的组件中。

Bundle被Intent维护,而Bundle这个类中,又维护了一个HashMap<String,Object>类型的集合。为了对其中的Map集合进行操作,Bundle提供了一系列putXxx()方法和getXxx()方法,对其中维护的Map集合插入及获取数据。而为了简化操作,Android在设计Intent的时候,为其提供了一系列的putXxx()方法用于向其内维护的Bundle对象插入数据,也提供了getExtras()方法,用于获取Intent内部维护的Bundle对象。

Bundle除了传递自定义的数据之外,对于一些Android系统内置的应用组件而言,也可以通过设置Intent内部定义好的一些Key,来指定开启Android系统内置的应用组件所需要的数据,这些Intent内部定义的Key,都是使用EXTRA_*的格式,很好辨认。如:使用隐式意图指定发送一封邮件,处理设置Action属性为"ACTION_SEND"之外,还需要使用Extra属性,通过EXTRA_EMAIL的Key来指定收件人,以及通过EXTRA_SUBJECT的Key来指定邮件的主题。

6.3.6 Flag

Flag,标识了Android通过启动Activity的方式,以确定开启后的Activity在回退栈中的维护过程。如果需要通过编码的方式指定Intent开启的Activity的启动模式,可以在Intent中使用setFlags(int)方法设置这个属性,它需要传递一个int类型的数据,被以静态常量的形式定义在Intent类中。

如果需要在清单文件中为Activity配置Flag属性来指定Activity的启动模式,可以在<activity…/>元素中,使用android:launchMode进行设置。 6ZPvNDBunF3vo1E3By74RRIjXcFeFnkhQ+4KPMDNWH9rHTrO9/1jMLgrjHTF0h6t

点击中间区域
呼出菜单
上一章
目录
下一章
×