构建Intent

Intent对象携带了Android系统用来确定要启动哪个组件的信息(例如,准确的组件名称或应当接收该Intent的组件类别),以及收件人组件为了正确执行操作而使用的信息(例如,要采取的操作以及要处理的数据)。

我们经常使用如下方法实现一个转跳:

Intent intent = new Inent(MainActivity.this,SecondActivity.class);
startActivity(intent);

其实这个写法还可以写作

Intent intent = new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
startActivity(intent);

这种启动方式被称之为“显式意图”,因为它直接指定了意图目标。

还有一种方式称之为“隐式意图”,我们不直接指定目标组件,而是通过设置Intent的各个属性来启动目标组件。

Intent主要由ComponentName、Action、Data、Category、Extra、Flag 六部分来组成,Intent通过调用setXXX()方法来设置其对应的属性,下面详细介绍各个属性。

  • ComponentName

    ComponentName用于标识位移的应用程序组件,即指明了期望的Intent,这种对象的名称是由目标组件的包名,与期望的类名组合而成,在Intent传递过程中,组件名称是一个可选项。当指定它时,便是显式的Intent消息;而当不指定它时,Android系统会根据其他信息,以及IntentFilter的过滤条件来选择相应的组件。
public class MainActivity extends Activity {

    private Button bt;

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

        bt = (Button) findViewById(R.id.bt);
        bt.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                ComponentName com = new ComponentName(MainActivity.this, SecondActivity.class);
                intent.setComponent(com);
                startActivity(intent);
            }
        });
    }
}
  • Action

    Action实际上就是一个描述了Intent所出发动作名称的字符串,在Intent类中,已经定义好很多字符串常量来表示不同的Action,当然开发人员也可以自定义Action

    常见的Action常量:

    • ACTION_CALL——播出Data里封装的电话号码

    • ACTION_EDIT——打开Data里指定数据所对应的编辑程序

    • ACTION_VIEW——打开能够显示Data之中封装的数据的应用程序

    • ACTION_MAIN——声明程序入口,该Activity并不会接收任何数据,同时结束后也不会返回任何数据

    • ACTION_BOOT_COMPLETED——BraodcastReceiver Action常量,表明系统启动完毕

    • ACTION_TIME_CHANGED——BraodcastReceiver Action常量,表示系统时间通过设置而改变

public class MainActivity extends Activity {

    private Button bt;

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

        bt = (Button) findViewById(R.id.bt);
        bt.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                Uri uri = Uri.parse("tel:10086"); 
                intent.setAction(Intent.ACTION_CALL);
                intent.setData(uri);
                startActivity(intent);
            }
        });
    }
}
  • Data

    Data主要是对Intent消息中数据的封装,主要描述Intent的动作所操作到底数据的URI及类型。不同类型的 Action会有不同的Data封装,例如打电话的Intent会封装tel://格式的电话URI,而ACTION_VIEW的Intent中Data则会封装http:// 格式的URI,正确的Data封装对Intent匹配请求同样非常重要

  • Category

    Category是对目标组件类别信息的描述,同样为一个字符串对象,一个Intent中可以包含多个Category,与Category相关的方法有三个:

    • 添加一个Category——addCategory

    • 删除一个Category——removeCategory

    • 得到一个Category——getCategory

    • Android系统同样定义了一组常量来表示Intent的不同类别,一些常见的Category常量

    • CATEGORY_GADGET,表示目标Activity是可以嵌入到其他Activity中的。

    • CATEGORY_HOME,表明目标Activity为HOME Activity。

    • CATEGORY_TAB,表明目标Activity是TabActivity的一个标签下的Activity。

    • CATEGORY_LAUNCHER,表明目标Activity是应用程序中最先被执行的Activity。

    • CATEGORY_PREFERNCE,表明目标Activity是一个偏好设置的Activity。

public class MainActivity extends Activity {

    private Button bt;

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

        bt = (Button) findViewById(R.id.bt);
        bt.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent=new Intent();
                intent.setAction("com.example.activitytest.ACTION_START");
                intent.addCategory("com.example.activitytest.MY_CATEGORY");
                startActivity(intent);
            }
        });
    }
}

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.intenttest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.CALL_PHONE" />

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

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="com.example.activitytest.MY_CATEGORY" />
            </intent-filter>
        </activity>
    </application>

</manifest>
  • Extra

    extra中封装了一些额外附加的信息,这些信息以键值对的形式存在,Intent可以通过putExtras()和getExtras()方法来存储和获取Extra,Android系统同样定义了一些Extra常量

    • EXTRA_CC,邮件抄送人邮箱地址。

    • EXTRA_EMAIL,装有邮件发送地址的字符串数组。

    • EXTRA_SUBJECT,当使用ACTION_SEND动作时,描述要发送邮件的主题。

    • EXTRA_TEXT,当使用ACTION_SEND动作时,描述要发送文本的信息。

  • Flags
    android中Intent的Flags有20多种,如下:

    • FLAG_GRANT_READ_URI_PERMISSION
    • FLAG_GRANT_WRITE_URI_PERMISSION
    • FLAG_DEBUG_LOG_RESOLUTION
    • FLAG_FROM_BACKGROUND
    • FLAG_ACTIVITY_BROUGHT_TO_FRONT
    • FLAG_ACTIVITY_CLEAR_TASK
    • FLAG_ACTIVITY_CLEAR_TOP
    • FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
    • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    • FLAG_ACTIVITY_FORWARD_RESULT
    • FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
    • FLAG_ACTIVITY_MULTIPLE_TASK
    • FLAG_ACTIVITY_NEW_TASK
    • FLAG_ACTIVITY_NO_ANIMATION
    • FLAG_ACTIVITY_NO_HISTORY
    • FLAG_ACTIVITY_NO_USER_ACTION
    • FLAG_ACTIVITY_PREVIOUS_IS_TOP
    • FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
    • FLAG_ACTIVITY_REORDER_TO_FRONT
    • FLAG_ACTIVITY_SINGLE_TOP
    • FLAG_ACTIVITY_TASK_ON_HOME
    • FLAG_RECEIVER_REGISTERED_ONLY

但是我们常用的只有4种

  • FLAG_ACTIVITY_CLEAR_TOP

    例如现在的栈情况为:A B C D 。D此时通过intent跳转到B,如果这个intent添加FLAG_ACTIVITY_CLEAR_TOP 标记,则栈情况变为:A B。如果没有添加这个标记,则栈情况将会变成:A B C D B。也就是说,如果添加了FLAG_ACTIVITY_CLEAR_TOP 标记,并且目标Activity在栈中已经存在,则将会把位于该目标activity之上的activity从栈中弹出销毁。这跟上面把B的Launch mode设置成singleTask类似。

  • FLAG_ACTIVITY_NO_HISTORY

    例如现在栈情况为:A B C。C通过intent跳转到D,这个intent添加FLAG_ACTIVITY_NO_HISTORY标志,则此时界面显示D的内容,如果此时D中又跳转到E,栈的情况变为:A B C E,此时按返回键会回到C,因为D根本就没有被压入栈中。

  • FLAG_ACTIVITY_SINGLE_TOP

    和上面Activity的 Launch mode的singleTop类似。如果某个intent添加了这个标志,并且这个intent的目标activity就是栈顶的activity,那么 将不会新建一个实例压入栈中。

  • FLAG_ACTIVITY_NEW_TASK

    例如现在栈1的情况是:A B C。C通过intent跳转到D,并且这个intent添加了FLAG_ACTIVITY_NEW_TASK 标 记,如果D这个Activity在Manifest.xml中的声明中添加了Task affinity,并且和栈1的affinity不同,系统首先会查找有没有和D的Task affinity相同的task栈存在,如果有存在,将D压入那个栈,如果不存在则会新建一个D的affinity的栈将其压入。如果D的Task affinity默认没有设置,或者和栈1的affinity相同,则会把其压入栈1,变成:A B C D,这样就和不加FLAG_ACTIVITY_NEW_TASK 标记效果是一样的了。

注意如果试图从非activity的非正常途径启动一个activity,比如从一个service中启动一个activity,则intent必须要添加 FLAG_ACTIVITY_NEW_TASK 标记。

Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1