使用Intent在活动之间穿梭

09 使用Intent在活动之间穿梭

Intent

定义

Intent是Android程序中各组件之间进行交互的一种重要方式

  • 可以指明当前组件想要执行的动作

  • 可以在不同组件之间传递数据

用途

Intent 一般可被用于启动活动、启动服务以及发送广播等场景

分类:

  • 显式Intent
  • 隐式Intent

Intent 作为一个负责组件间传递消息的信息对象,最重要的就是其包含的信息。实际上无论是显式还是隐式,Intent 发出的时候,系统对应的行为正是由 Intent 所包含信息的组合决定。一个 Intent 所包含的信息如下图:

img

目标

启动活动

一、使用显式Intent

新建活动emptyActivity->SecondActivity

image-20201223142116091

image-20201223142212223

image-20201223142257641

  1. 修改second_layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!--
            定义一个按钮Button 2
        -->
        <Button
            android:id="@+id/button_2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button 2"></Button>
    </LinearLayout>
    
  2. SecondActivity.java

    package com.example.myactivitytest;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    
    public class SecondActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.second_layout);
        }
    }
    
  3. AndroidManifest.xml中注册

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.myactivitytest">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.MyActivityTest">
            
            <!--
                Android studio已经帮我们把SecondActivity注册了
                SecondActivity不是主活动,所以不用配置 <intent-filter>
            -->
            <activity android:name=".SecondActivity" />
            
            <activity
                android:name=".FirstActivity"
                android:label="This is FirstActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    
  4. 修改FirstActivity.java中Button1的点击事件button1.setOnClickListener()

    package com.example.myactivitytest;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    
    public class FirstActivity extends AppCompatActivity {
        /*
            项目中的任何活动都需要重写Activity的onCreate()方法
         */
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            /*
                调用setContentView()方法给当前活动加载布局
                传入参数为布局文件的id
                项目中添加的任何资源都会在R文件中生成一个相应的资源id
                我们把创建的first_layout.xml布局的id已经添加到了R文件中
                Resource:资源
                所有的活动在AndroidManifest.xml中注册才能生效
                Android studio可以帮我们自动在xml中注册
             */
            setContentView(R.layout.first_layout);
            /*
                定义一个Toast的触发点
                通过findViewById()方法获取到在布局文件中定义的元素
                @return 返回一个View对象,我们需要向下转型,将它转成Button对象
                传入R.id.button_1得到按钮的实例android:id="@+id/button_1"
             */
    
            Button button1 = (Button) findViewById(R.id.button_1);
            /*
                调用setOnClickListener()为按钮注册一个监听器
                点击按钮就会执行监听器的onClick()方法
                弹出Toast的功能需要写在onClick()方法中
             */
            button1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    /*
                        在FirstActivity这个活动的基础上打开SecondActivity这个活动
                        然后通过startActivity()方法来执行这个Intent
                        1. 构建一个Intent
                        2. 传入FirstActivity.this作为上下文
                        3. 传入SecondActivity.class作为目标活动
                     */
                    Intent intent = new Intent(
                            FirstActivity.this,SecondActivity.class);
                    //startActivity传入一个Intent对象
                    startActivity(intent);
                }
            });
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            /*
                通过getMenuInflater()方法得到MenuInflater对象
                再调用inflate()方法就可以给当前活动创建菜单
                两个参数:
                指定我们通过哪个资源文件来创建菜单:R.menu.main
                指定我们菜单项将添加到哪一个menu对象中:
                    menu,就是onCreateOptionsMenu方法的参数
                @return boolean:
                true
                表示允许创建的菜单显示出来
                false
                创建的菜单将无法显示
             */
            getMenuInflater().inflate(R.menu.main,menu);
            //return super.onCreateOptionsMenu(menu);
            return true;
        }
    
        /**
         * 通过调用item.getItemId()来判断我们点击的是哪一个菜单项
         * @param item
         * @return
         */
        @Override
        public boolean onOptionsItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()){
                case R.id.add_item:
                    Toast.makeText(this,"你点击了Add",Toast.LENGTH_SHORT).show();
                    break;
                case R.id.remove_item:
                    Toast.makeText(this,"你点击了Remove",Toast.LENGTH_SHORT).show();
                    break;
                default:
            }
            return true;
        }
    }
    

    运行程序

    image-20201223144939529

    点击button1后的界面

image-20201223144958138

二、使用隐式Intent

隐式Intent并不明确指出我们要启动哪一个活动,交给系统去帮我们找到合适的活动,然后再启动

  1. 配置 <intent-filter>内容

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.myactivitytest">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.MyActivityTest">
            <!--
                Android studio已经帮我们把SecondActivity注册了
                SecondActivity不是主活动,所以不用配置 <intent-filter>
                -->
            <activity android:name=".SecondActivity" >
                <!--
                     在<action>标签中我们指明了当前活动
                     可以响应com.example.myactivitytest.ACTION_START这个action
                     而<category>标签则包含了一些附加信息,更精确地指明了当前的活动能
                     够响应的Intent中还可能带有的category。
                     只有<action>和<category>中的内容同时能够
                     匹配上Intent中指定的action和 category时,
                     这个活动才能响应该Intent。
                           -->
                <intent-filter>
                    <action android:name="com.example.myactivitytest.ACTION_START" />
                    <category android:name="android.intent.category.DEFAULT"/>
    
                </intent-filter>
            </activity>
    
            <activity
                android:name=".FirstActivity"
                android:label="This is FirstActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    
  2. 修改FirstActivity.java中Button1的点击事件button1.setOnClickListener()

            button1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    /*
                        在FirstActivity这个活动的基础上打开SecondActivity这个活动
                        然后通过startActivity()方法来执行这个Intent
                        1. 构建一个Intent
                        2. 传入FirstActivity.this作为上下文
                        3. 传入SecondActivity.class作为目标活动
                     */
                    //Intent intent = new Intent(
                            //FirstActivity.this,SecondActivity.class);
                    //startActivity传入一个Intent对象
                    Intent intent = new Intent("com.example.myactivitytest.ACTION_START");
                    //android.intent.category.DEFAULT是一种默认的category,
                    //在调用startActivity()方法的时候会自动将这个category添加到Intent中
                    startActivity(intent);
                }
            });
        }
    

    每个Intent中只能指定一个action,但却能指定多个category

    category一定要在Java文件和中同时声明,缺一不可

三、其他隐式Intent

使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。

在应用程序中展示一个网页的Intent

比如说你的应用程序中需要展示一个网页,这时你没有必要自己去实现一个浏览器(事实上也不太可能),而是只需要调用系统的浏览器来打开这个网页就行了。

  1. 修改FirstActivity.java中Button1的点击事件button1.setOnClickListener()

            button1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    /*
                        更多隐式Intent
                        Intent.ACTION_VIEW 安卓系统内置动作
                             public static final String ACTION_VIEW = "android.intent.action.VIEW"
                     */
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    /*
                        通过Uri.parse()方法,将一个网址字符串解析成一个uri对象,
                        再调用Intent的 setData()方法将这个Uri对象传递进去。
                     */
                    intent.setData(Uri.parse("http://www.baidu.com"));
                    startActivity(intent);
                }
            });
        }
    
    1. 运行后点击button1结果:

image-20201223153929444

可以在<intent-filter>标签中再配置一个<data>标签,用于更精确地指定当前活动能够响应什么类型的数据。

`标签中主要可以配置以下内容

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

建立一个活动,响应打开网页的Intent

  1. 新建ThirdActivity.java

  2. third_layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!--
               定义一个按钮Button 3
           -->
        <Button
            android:id="@+id/button_3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button 3"></Button>
    </LinearLayout>
    
  3. 修改AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.example.myactivitytest">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.MyActivityTest">
            
            <activity android:name=".ThirdActivity">
                <intent-filter tools:ignore="AppLinkUrlError">
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT"/>
                    <data android:scheme="http"/>
                </intent-filter>
            </activity>
            <!--
                Android studio已经帮我们把SecondActivity注册了
                SecondActivity不是主活动,所以不用配置 <intent-filter>
            -->
            <activity android:name=".SecondActivity">
                <!--
                     在<action>标签中我们指明了当前活动
                     可以响应com.example.myactivitytest.ACTION_START这个action
                     而<category>标签则包含了一些附加信息,更精确地指明了当前的活动能
                     够响应的Intent中还可能带有的category。
                     只有<action>和<category>中的内容同时能够
                     匹配上Intent中指定的action和 category时,
                     这个活动才能响应该Intent。
                -->
                <intent-filter>
                    <action android:name="com.example.myactivitytest.ACTION_START" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
            <activity
                android:name=".FirstActivity"
                android:label="This is FirstActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>
    

image-20201223160120543

选择chrome

image-20201223160230991

选择MyActivityTest

image-20201223160304057

另:

FirstActivity.java

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                /*
                    更多隐式Intent
                    Intent.ACTION_VIEW 安卓系统内置动作
                         public static final String ACTION_VIEW = "android.intent.action.VIEW"
                 */
                Intent intent = new Intent(Intent.ACTION_VIEW);
                /*
                    通过Uri.parse()方法,将一个网址字符串解析成一个uri对象,
                    再调用Intent的 setData()方法将这个Uri对象传递进去。
                 */
                intent.setData(Uri.parse("tel:10086"));
                startActivity(intent);
            }
        });
    }

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.myactivitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyActivityTest">
        <activity android:name=".ThirdActivity">
            <intent-filter tools:ignore="AppLinkUrlError">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:scheme="tel"/>
            </intent-filter>
        </activity>
        <!--
            Android studio已经帮我们把SecondActivity注册了
            SecondActivity不是主活动,所以不用配置 <intent-filter>
        -->
        <activity android:name=".SecondActivity">

            <!--
                 在<action>标签中我们指明了当前活动
                 可以响应com.example.myactivitytest.ACTION_START这个action
                 而<category>标签则包含了一些附加信息,更精确地指明了当前的活动能
                 够响应的Intent中还可能带有的category。
                 只有<action>和<category>中的内容同时能够
                 匹配上Intent中指定的action和 category时,
                 这个活动才能响应该Intent。
            -->
            <intent-filter>
                <action android:name="com.example.myactivitytest.ACTION_START" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".FirstActivity"
            android:label="This is FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

点击Button1

image-20201223160800045

选择Phone

image-20201223160823171

image-20201223160836930

四、向下一个活动传递数据

可以在启动活动的时候传递数据

  • Intent 中提供了一系列 putExtra()方法的重载,可以把我们想要传递的数据暂存在Intent中,

  • 启动了另一个活动后,只需要把这些数据再从Intent中取出就可以

eg:

  1. 把FirstActivity中的一个字符串传递到SecondActivity中

    button1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    /*
                        向下一个活动传递数据
                     */
                    String data = "毁灭吧,我累了!";
                    Intent intent = new Intent(
                            FirstActivity.this,SecondActivity.class);
                    /*
                    putExtra()方法接收两个参数
                        第一个参数是键,用于后面从Intent中取值
                        第二个参数是value,是真正要传递的数据。
    
                     */
                    intent.putExtra("extra_data",data);
                    startActivity(intent);
                }
            });
    
  2. 在 SecondActivity 中将传递的数据取出,并打印出来

    package com.example.myactivitytest;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    
    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()、getBooleanExtra()等
            */
            String data = intent.getStringExtra("extra_data");
            Log.d("SecondActivity",data);
        }
    }
    

    image-20201223164342682

运行程序

在logcat中查看debug日志

image-20201223164612358

五、返回数据给上一个活动

Activity中还有一个startActivityForResult()方法也是用于启动活动的,但这个方法期望在活动销毁的时候能够返回一个结果给上一个活动。

startActivityForResult()方法接收两个参数

  • 第一个参数是Intent
  • 第二个参数是请求码,用于在之后的回调中判断数据的来源
  1. 修改FirstActivity中的按钮点击事件

            button1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    /*
                        返回数据给上一个活动
                        startActivityForResult()方法接收两个参数
                            - 第一个参数是Intent
                            - 第二个参数是请求码,用于在之后的回调中判断数据的来源
                     */
                    Intent intent = new Intent(
                            FirstActivity.this,SecondActivity.class);
                    //使用startActivityForResult()方法来启动SecondActivity
                    // 请求码只要是一个唯一值就可以了,这里传入了1
                    startActivityForResult(intent,1);
                }
            });
    
  2. 在SecondActivity中给按钮注册点击事件,并在点击事件中添加返回数据的逻辑

    package com.example.myactivitytest;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class SecondActivity extends AppCompatActivity {
    
        @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 = new Intent();
                    intent.putExtra("data_return", "跟得上我的脚步吗?");
                    /*
                        setResult()专门用于向上一个活动返回数据
                        传入两个参数:
                            第一个参数用于向上一个活动返回处理结果
                                一般只使用RESULT_OK 或RESULT_CANCELED
                            第二个参数则把带有数据的Intent传递回去
                     */
                    setResult(RESULT_OK, intent);
                    //调用了finish()方法来销毁当前活动
                    finish();
                }
            });
        }
    }
    
  3. 我们使用startActivityForResult()方法来启动SecondActivity,在SecondActivity被销毁之后会回调上一个活动的onActivityResult()方法,因此我们需要在FirstActivity中重写这个方法来得到返回的数据。

     /**
         * onActivityResult()方法带有三个参数
         * @param requestCode 第一个参数requestCode,我们在启动活动时传入的请求码(startActivityForResult(intent,1);)
         * @param resultCode  第二个参数resultCode,我们在返回数据时传入的处理结果
         * @param data        第三个参数data,携带着返回数据的Intent
         */
        @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            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:
            }
        }
    

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

    运行程序,在FirstActivity的界面点击按钮会打开SecondActivity ,然后在SecondActivity界面点击Button 2按钮会回到FirstActivity,这时查看logcat 的打印信息

image-20201223210913840

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值