Android开发 - Intent

什么是Intent

Intent是Android程序总各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以再不同组件之间传递数据。Intent一般可用于启动活动、启动服务以及发送广播等场景。

Intent分类

  • 显示Intent

Intent有很多构造函数重载,其中一个是Intent(Context packageContext, Class<?>cls)。该函数接受两个参数,第一个参数是Context要求提供一个启动活动的上下文,第二个参数Class则是指定想要启动的目标活动,通过这个构造函数就可以创建出Intent的“意图”。再使用startActivity()方法启动活动,该方法接收一个Intent参数,只需要将上边创建好的Intent传入该函数即可

创建两个Activity,FirstActivity(主活动)和SecondActivity,在FirstActivity中创建一个按钮,点击之后进入SecondActivity

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
        Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                // 构建Intent,传入FirstActivity.this作为上下文,传入SecondActivity.class作为目标活动
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                // 这样"意图"就比较明显了,即在FirstActivity这个活动的基础上打来SecondActivity这个活动,执行Intent
                startActivity(intent);
            }
        });
    }

运行后就可以成功启动SecondActivity了,如果想回到上一个活动,只要按下Back键就可以销毁当前活动,回到上一个活动了

  • 使用隐式Intent

相比于显式Intent,隐式Intent并不明确指出想要启动哪一个活动,而是指定一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并找出合适的活动去启动

那么什么是合适的活动呢?简答来说就是可以响应这个隐式Intent的活动。对于SecondActivity可以响应什么样的隐式Intent呢?通过在<activity>标签下配置<intent-filter>的内容,可以指定当前活动能够响应的action和category,打开AndroidMainfest.xml,添加如下代码

<activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="com.znty.activitytest.ACTION_START" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

在<action>标签中,指明了当前活动可以响应com.znty.xietao.activitytest.ACTION_START这个action,而<category>标签则包含了一些附加信息,更明确地指明了当前的活动能够响应的Intent中还可能带有category。只有<action>和<category>中的内容同时能够匹配上Intent中指定的action和category时,这个活动才能响应该Intent(就是起个名和分个类)。

回到FirstActivity中的按钮事件,修改为:

Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.znty.activitytest.ACTION_START");
                startActivity(intent);
            }
        });

可以看到使用了Intent的另外一个构造函数,直接将action的字符串传进去,表明想要启动能够响应“com.znty.xietao.activitytest.ACTION_START”这个action的活动,由于category设置的是DEFAULT,这是一种默认的category,在调用startActivity()方法的时候会自动将这个category添加到Intent中。

重新运行程序,可以得到和显示Intent使用一样的效果,这里使用的是隐式Intent,这就说明了在<activity>标签下设置的action和category的内容生效了

每个Intent只能指定一个action,但却能指定多个category。现在在Intent中除了默认的category,再添加一个category。调用Intent的addcategory()方法来添加一个category

Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.znty.activitytest.ACTION_START");
                intent.addCategory("com.zntq.activitytest.MY_CATEGORY");
                startActivity(intent);
            }
        });

同时需要在AndroidManifest.xml中进行设置,否则的话整个程序就会直接闪退

<activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="com.znty.activitytest.ACTION_START" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="com.zntq.activitytest.MY_CATEGORY" />
            </intent-filter>
        </activity>

这样再一次运行之后,就会发现一切都正常了

更多隐式Intent的用法

使用隐式Intent不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如在应用程序中需要展示一个网页,只需要调用系统的浏览器来打开这个网页就行

Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_VIEW);
                // Intent.ACTION_VIEW是一个Android系统内置的动作,它的常量值是"android.intent.action.VIEW"
                intent.setData(Uri.parse("http://www.baidu.com"));
                // 通过Uri.parse()方法,将一个网址字符串解析成一个UR对象,再调用Intent的setData()方法将这个Uri对象传进去
                // setData()方法,它接收一个Uri对象,主要用于指定当前Intent正在操作的数据,而这些数据通常都是以字符串的形式传入到Uri.parse()方法中进行解析产生的。
                startActivity(intent);
            }
        });

与上边的对应,还可以再<intent-filter>标签中再配置一个<data>标签,用于更精确地指定当前活动能够响应什么类型的数据。<data>标签中主要可以配置以下内容

  • android:scheme。用于指定数据的协议部分,如上例中的http部分。
  • android:host。用于指定数据的主机名部分,如上例中的www.baidu.com部分。
  • android:port。用于指定数据的端口部分,一般紧随在主机名之后。
  • android:path。用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的部分。
  • android:mineType。用于指定可以处理的数据类型,允许使用通配符的方式进行指定。

只有<data>标签中指定的内容和Intent中携带的Data完全一致时,当前活动才能够响应该Intent。不过<data>标签都不会指定过多的内容,如上边例子中,其实只需要指定android:scheme为http,就可以响应所有的http协议的Intent了。

调用系统打电话功能,改变FirstActivity中按钮想打电话的“意图”,data部分指定的协议时10086,当然还可以指定其他很多协议,如geo表示显示地理位置等

Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                // 响应打电话功能
                Intent intent = new Intent(Intent.ACTION_DIAL);
                intent.setData(Uri.parse("tel:10086"));
                startActivity(intent);
            }
        });

向下一个Intent传递数据

Intent不仅能启动Activity,还可以再启动Activity的时候传递数据。它的思路很简单,Intent提供了一系列putExtra()方法的重载,可以把想要传递的数据暂存在Intent中,启动了另一个活动之后,只需要把这些数据再从Intent中取出来就可以了。

比如FirstActivity中有一个字符串,现在想把这个字符串传递到SecondActivity中,可以这样编写

在FirstActivity中:

Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                String data = "Hello SecondActivity";
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                intent.putExtra("extra_data", data); 
                // 第一个参数是键,用于后边的取值,第二个参数是真正的数据
                startActivity(intent);
            }
        });

在SecondActivity中接收数据:

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
        // 通过getIntent()方法获取到用于SecondActivity的Intent
        Intent intent = getIntent();
        // 调用getStringExtra()方法来获取传递的数据,用键来取
        // 如果传递的是整型数据,则使用getIntExtra()方法;传递的是布尔型数据getBoolExtra()方法
        String data = intent.getStringExtra("extra_data");
        System.out.println(data);
        Log.d("SecondActivity", data);
    }
}

返回数据给上一个Activity

返回上一个活动只需要按一下Back键就可以了,并没有一个用于启动活动Intent来传递数据。Activity还有一个startActivityForResult()方法也适用于启动活动的,但是这个方法期望在活动销毁的时候能够返回一个结果给上一个活动,这就是我们所需要的。

startActivityForResult()方法接收两个参数,第一个参数还是Intent,第二个参数是请求码,用于之后的回调中判断数据的来源

修改FirstActivity中按钮的点击事件

Button button = (Button)findViewById(R.id.button_1);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                // 使用startActivityForResult()方法来启动Activity,请求码只要是一个唯一值就可以了,这里传入1
                startActivityForResult(intent, 1);
            }
        });

在SecondActivity中给按钮注册事件

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
        // 给按钮注册点击事件,并在点击事件中添加返回数据的逻辑
        Button button2 = (Button)findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 创建一个Intent,该Intent仅仅用于传递数据,没有指定任何的"意图"
                Intent intent = new Intent();
                // 把数据存放在Intent中
                intent.putExtra("data_return", "Hello FirstActivity");
                // 调用setresult()方法,该方法是专门用于向上一个页面传递数据的。接收两个参数,第一个参数
                // 用于向上一个活动返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED这两个值,第二个参数则把
                // 带有数据的Intent传递回去
                setResult(RESULT_OK, intent);
                // 调用finish()方法来销毁当前活动
                finish();
            }
        });
    }

在SecondActivity销毁之后会回调上一个活动的onActivityResult()方法,再回到FirstActivity

// 由于使用 startActivityForResult()方法来启动SecondActivity的,在SecondActivity被销毁之后会回调
    // 上一个活动也就是FirstActivity的onActivityResult()方法,因此重写该方法
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // 该方法接收三个参数,第一个参数requestCode,就是启动活动时传入的请求码,第二个参数resultCode,即返回数据时
        // 传入的处理结果,第三个参数就是携带者返回数据的Intent
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case 1:
                if (resultCode == RESULT_OK) {
                    String returnedData = data.getStringExtra("data_return");
                    Log.d("FirstActivity", returnedData);
                }
                break;
            default:
        }
    }

由于在一个Activity中有可能调用startActivityForResult()方法去启动很多不同的Activity,每一个Activity返回的数据都会回调到onActivityResult()这个方法中,因此首先要通过检查requestCode的值来判断数据源。确定数据是从SecondActivity返回的之后,再通过resultCode的值来判断处理结果是否成功,最后从data中取值并打印,这样就完成了向上一个Activity返回数据的工作。

如果用户在SecondActivity中并不是通过点击按钮而是通过按下Back键回到FirstActivity,这时候需要在SecondActivity中重写onBackPressed()方法来解决:

@Override
    public void onBackPressed() {
        super.onBackPressed();
        Intent intent = new Intent();
        intent.putExtra("data_return", "Hello FirstActivity");
        setResult(RESULT_OK, intent);
        finish();
    }

这样当用户按下Back键,就会执行onBackPressed()方法中的代码,从而在这里添加返回数据的逻辑就行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • Intent 是一个消息传递对象,您可以使用它从其他应用组件请求操作。尽管 Intent 可以通过多种方式促进组件...
    牧童遥指2000阅读 5,059评论 0 12
  • 作为Android的四大组件之一,活动最先走进我们的视野,其重要性不言而喻,今天就抽出时间来专门对Android活...
    loser先生阅读 863评论 0 0
  • 如果一个 Intent 请求在一片数据上执行一个动作, Android 如何知道哪个应用程序(和组件)能用来响应这...
    柒黍阅读 5,747评论 0 1
  • 01. 你说,你爱我 可我却忘了问 你爱的,是不是只有我 02. 分手那天,阳光明媚 可我的心 却凉了一丝 03....
    一个喜欢深夜读书的女子阅读 630评论 4 21
  • 有这样一种人 遇到一些伤心的事,想要去向朋友倾诉,于是用开玩笑的语气跟她倾诉了,她会安慰我。 后来,遇到了已经开不...
    听你的声音阅读 139评论 0 0