Android 第二课 Intent

上一节,掌握了活动的创建,但是在启动器中点击应用的图标只会进入到该应用的主活动,那么,如何从主活动跳转到其他活动呢?

  • 显式Intent

             Intent有多个构造函数,其中一个是Intent(Context packContext,Class<?>cls),这个构造函数接收两个参数,一个参数Context要求提供一个启动活动的上下文,第二个参数Class则是想要启动的目标活动。

  Intent intent = new Intent(FirstActivity.this,SecondActivity.class);//构造一个Intent
  startActivity(intent);// Activity类中提供了一个startActivity()方法,这个方法专门用来启动活动

        实现功能:通过在FirstActivity这个活动的基础上打开SecondActivity这个活动
  • 隐式Intent
  • 更多隐式Intent用法

        setData()方法接收一个Uri对象,主要用于指定当前Intent正在操作的数据,而这些数据通常都是以字符串形式传入到Uri.parse()方法解析产生的。

intent.setData(Uri.parse("https://www.baidu.com"));
  • 向下一个活动传递数据

putExtra()方法传递了一个字符串,这里putExtra()方法接收两个参数,第一个是键(类似于id),用于后面从Intent中取值,第二个参数才是要传递的数据。

  • 返回数据给上一个活动

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

------------------------------------------------------------------------------------

下面具体分析:

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

Intent 分为显示Intent和隐式Intent。

  • 显式Intent

快速在ActivityTest中创建一个活动,右击com.example.activitytest包new一个Empty Activity,将活动命名为SecondActivity,并勾选Generate Layout File,给布局文件命名为second_layout,但不要勾选Launcher Activity选项。 完成创建会生成SecondActivity.java和second_layout.xml两个文件,编辑second_layout.xml文件,添加代码(添加一个Button),代码如下:(勾选Generate Layout File,会自动生成SecondActivity.java和second_layout.xml两个文件,并且second_layout.xml会在SecondActivity.java加载,不勾选Generate Layout File不会自动生成second_layout.xml这个文件,需要再手动创建,并在SecondActivity.java加载second_layout.xml即在onCreate()方法中添加:setContentView(R.layout.second_layout);)

<?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
        android:id="@+id/button_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 2"/>
</LinearLayout>

另外,每一个活动都需要在AndroidManifest.xml文件中注册,不过这一步,AS已经自动完成了。打开AndroidManifest.xml文件,代码如下:

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

    <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/AppTheme">
        <activity android:name=".FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

因为SecondActivity不是主活动,因此不需要配置<intent-filter>标签里的内容。

    Intent有多个构造函数,其中一个是Intent(Context packContext,Class<?>cls),这个构造函数接收两个参数,一个参数Context要求提供一个启动活动的上下文,第二个参数Class则是想要启动的目标活动。

    Activity类中提供了一个startActivity()方法,这个方法专门用来启动活动,它接收一个Intent参数,这里我们将构建好的Intent传入startActivity()方法就可以启动目标活动了,修改FirstActivity的按钮事件,代码如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_activity);

        Button button1 = (Button)findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
               // Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();提醒
                
                Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                startActivity(intent);
                
            }
        });
    }

先构建出一个Intent,以FirstActivity.this为上下文,传入SecondActivity.class为目标活动。即在FirstActivity这个活动的基础上打开SecondActivity这个活动,然后通过startActivity()方法来执行这个Intent。

现在可以运行程序了。

按back键就可以销毁当前活动,返回上一个活动。

  • 隐式Intent

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

    所谓合适的活动是指:可以相应我们这个隐式Intent的活动。目前SecondActivity还无法去响应隐式Intent。

通过在<activity>标签下配置<intent-filter>的内容,可以指定当前活动能够响应的action和category,打开ActivityManifest.xml文件中,添加如下代码:

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

我们指明了当前活动可以响应com.example.activitytest.ACTION_START这个action,更精确的指明了当前活动能够响应的Intent中可能还带有的category。并且,只有<action>和<category>中的内容同时能够匹配上Intent中指定的action和category时,这个活动才能响应该Intent

修改FirstActivity中按钮的点击事件,代码如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_activity);

        Button button1 = (Button)findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
               // Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();提醒
                
                //Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                //startActivity(intent);
                
                Intent intent = new Intent("com.example.activitytest.ACTION_START");
                startActivity(intent);

            }
        });
    }

    这里是Intent的另一个构造函数,直接将action的字符串传了进去,表明我们想要启动能够响应com.example.activitytest.ACTION_START这个action 的活动。因为android.intent.category.DEFAULT是一种默认的category,但是在调用startActivity()方法的时候会自动将这个默认的category添加到Intent中,所以可以不用写android.intent.category.DEFAULT这条代码,而且编译之后,也不会再Intent里自动添加。

现在又可以运行一下程序。

        每个Intent中只能指定一个action,但却能指定多个category。现在我们只有一个默认的category(并且这条语句并不存在。)我们可以再添加一个自定义category。

修改FirstActivity中的按钮的点击事件。代码如下:

  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_activity);

        Button button1 = (Button)findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
               // Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();提醒

                //Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                //startActivity(intent);

                Intent intent = new Intent("com.example.activitytest.ACTION_START");
                intent.addCategory("com.example.activitytest.MY_CATEGORY");
                startActivity(intent);

            }
        });
    }

    我们指定了一个自定义的category,值为com.example.activitytest.MY_CATEGORY。那我们是不是也可以指定一个自定义的category,值为com.example.activitytest.MYYY_CATEGORY呢?

重新运行成我们发现程序崩溃了,在logcat界面查看错误日志,我们发现没有任何一个活动可以响应我们的Intent,因为我们刚刚在Intent中新增了一个category,而SecondActivity的<intent-filter>标签中并没有声明这个category。

那这样看来,我们是不是可以在SecondActivity的<intent-filter>标签中声明这个category,来挽救这个程序呢?

我们姑且一试。发现是可以的,程序又正常了。代码如下:

<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>
这样或许才算是真正意义上的“只有<action>和<category>中的内容同时能够匹配上Intent中指定的action和category时,这个活动才能响应该Intent”

  • 更多隐式Intent的用法

使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。好比你需要展示一个网页,但是你没必要自己去实现一个浏览器,只需要调用系统的浏览器即可。

修改FirstActivity中的按钮点击事件的代码,如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_activity);

        Button button1 = (Button)findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
               // Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();//提醒

                //Intent intent = new Intent(FirstActivity.this,SecondActivity.class);//显示Intent
                //startActivity(intent);//启动intent

                //Intent intent = new Intent("com.example.activitytest.ACTION_START");//1个Intent,1个默认的category(DEFAULT),1个自定义的category(MY_CATEGORY)
                //intent.addCategory("com.example.activitytest.MY_CATEGORY");
                //startActivity(intent);
                
                Intent intent = new Intent(Intent.ACTION_VIEW);//ACTION_VIEW是一个Android系统内置的动作,其常量值为android.intent.action.VIEW
                intent.setData(Uri.parse("https://www.baidu.com"));
                startActivity(intent);
                
            }
        });
    }

        首先指定了action是Intent.ACTION_VIEW,这是一个android系统的内置动作,其常量值为android.intent.action。然后将Uri.parse()方法将一个网址字符串解析成一个Uri对象,再调用Intent的setData()方法将这个Uri对象传递进去。setData()方法接收一个Uri对象,主要用于指定当前Intent正在操作的数据,而这些数据通常都是以字符串形式传入到Uri.parse()方法解析产生的。我们还可以在<intent-filter>标签中再配置一个<data>标签,用于精确地指定当前活动能够响应什么类型的数据。只有<data>标签中指定的内容和Intent中携带的Data完全一致时,当前活动才能够响应该Intent.

让我们再新建一个ThirdActivity,接着详解上面的内容。

右击com.example.activitytest,new一个Empty Activity,新建ThirdActivity,首先不勾选Generate Layout File,因为作者发现自己勾选之后,产生Root element的不是默认的LinearLayout类型的,而是其他类型,在这里,我们分别手动创建Activity和对应的布局文件,并在onCreate()中添加加载语句:setContentView(R.layout.third_layout);

ThirdActivity创建完成后,编辑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
        android:id="@+id/button_3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:text="Button 3"/>

</LinearLayout>

简言之,就是添加了一个Button。

然后在AndroidManifest.xml文件中修改ThirdActivity中注册信息,代码如下(我们只包含ThirdActivity):

<activity android:name=".ThirdActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:scheme="http"/>
            </intent-filter>
</activity>

其中,这个<acitivity>是自动帮我们注册,里面的<intent-filter>是需要我们手动写入的。我们在<intent-filter>中配置了当前活动能够响应的action是Intent.ACTION.VIEW的常量值,而category则毫无疑问制定了默认的category值,另外在<data>我们通过android:scheme指定了数据的协议必须是http协议,这样ThirdActivity应该就和浏览器一样,能够响应一个打开网页的Intent了。

现在我们又可以去运行一下程序了。除了http协议,我们还可以指定其他许多协议,比如geo表示显示地理位置,tel表示拨打电话,我们可以在程序中调用系统拨号界面。代码如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_activity);

        Button button1 = (Button)findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
               // Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();提醒

                //Intent intent = new Intent(FirstActivity.this,SecondActivity.class);//显示Intent
                //startActivity(intent);//启动intent

                //Intent intent = new Intent("com.example.activitytest.ACTION_START");//1个Intent,1个默认的category(DEFAULT),1个自定义的category(MY_CATEGORY)
                //intent.addCategory("com.example.activitytest.MY_CATEGORY");
                //startActivity(intent);

               // Intent intent = new Intent(Intent.ACTION_VIEW);//ACTION_VIEW是一个Android系统内置的动作,其常量值为android.intent.action.VIEW
               // intent.setData(Uri.parse("https://www.baidu.com"));
                // startActivity(intent);
                
                Intent intent = new Intent(Intent.ACTION_DIAL);//ACTION_DIAL是一个Android 系统的内置动作,在Data部分指定了协议是tel,号码是10086.
                intent.setData(Uri.parse("tel:10086"));
                startActivity(intent);
            }
        });

现在我们又可以运行一下程序了。

  • 向下一个活动传递数据

我们可以简单的使用Intent来启动一个活动,其实Intent还可以在启动活动的时候传递数据。

Intent中提供了一些列putExtra()方法的重载,可以把我们想要传递的数据暂存在intent中,启动了另一个活动后,只需要把这些数据再从Intent中取出就可以了,可以在FirstActivity中定义一个字符串,现在想把这个字符串传递到SecondActivity中,可以这样编写,代码如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_activity);

        Button button1 = (Button)findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
               // Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();提醒

                //Intent intent = new Intent(FirstActivity.this,SecondActivity.class);//显示Intent
                //startActivity(intent);//启动intent

                //Intent intent = new Intent("com.example.activitytest.ACTION_START");//1个Intent,1个默认的category(DEFAULT),1个自定义的category(MY_CATEGORY)
                //intent.addCategory("com.example.activitytest.MY_CATEGORY");
                //startActivity(intent);

               // Intent intent = new Intent(Intent.ACTION_VIEW);//ACTION_VIEW是一个Android系统内置的动作,其常量值为android.intent.action.VIEW
               // intent.setData(Uri.parse("https://www.baidu.com"));
                // startActivity(intent);

                //Intent intent = new Intent(Intent.ACTION_DIAL);//ACTION_DIAL是一个Android 系统的内置动作,在Data部分指定了协议是tel,号码是10086.
                //intent.setData(Uri.parse("tel:10086"));
                //startActivity(intent);
                
                String data = "Hello SecondActivity";
                Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                intent.putExtra("extra_data",data);
                startActivity(intent);
            }
        });
    }

我们是使用显式Intent来启动SecondActivity,并通过putExtra()方法传递了一个字符串,这里putExtra()方法接收两个参数,第一个是键(类似于id),用于后面从Intent中取值,第二个参数才是要传递的数据。

然后我们要在SecondActivity中将要传递的数据取出,并打印出来。(在SecondActivity.java文件进行操作)代码如下:

public class SecondActivity extends AppCompatActivity {

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

        Intent intent = getIntent();
        String data = intent.getStringExtra("extra_data");
        Log.d("SecondActivity",data);
    }
}

首先通过getIntent()方法来获取到用来启动SecondActivity的Intent,然后调用getStringExtra()方法来获取传递的数据,如果传递的数据是整型,则调用getIntExtra()方法,如果传递的是布尔类型数据,则调用getBooleanExtra()方法。

现在,我们又可以运行程序了。点击Button1 会跳转到SecondActivity,查看logcat打印信息。我们可以看到从FirstActivity传递来的数据。

  • 返回数据给上一个活动

既然可以给下一个活动传递数据,是不是也可以给上一个活动返回数据呢?不过不同的是,返回上一个活动只需要按一下Back键就可以了,没有一个用于启动活动的Intent来传递数据。

查阅文档会发现:

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

    startActivityForResult()方法接收两个参数,第一个参数是Intent;第二个参数是请求码,用于在之后的回掉中判断数据的来源。修改FirstActivity中按钮的点击事件,代码如下:

public void onClick(View view) {
               // Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();提醒

                //Intent intent = new Intent(FirstActivity.this,SecondActivity.class);//显示Intent
                //startActivity(intent);//启动intent

                //Intent intent = new Intent("com.example.activitytest.ACTION_START");//1个Intent,1个默认的category(DEFAULT),1个自定义的category(MY_CATEGORY)
                //intent.addCategory("com.example.activitytest.MY_CATEGORY");
                //startActivity(intent);

               // Intent intent = new Intent(Intent.ACTION_VIEW);//ACTION_VIEW是一个Android系统内置的动作,其常量值为android.intent.action.VIEW
               // intent.setData(Uri.parse("https://www.baidu.com"));
                // startActivity(intent);

                //Intent intent = new Intent(Intent.ACTION_DIAL);//ACTION_DIAL是一个Android 系统的内置动作,在Data部分指定了协议是tel,号码是10086.
                //intent.setData(Uri.parse("tel:10086"));
                //startActivity(intent);

                //String data = "Hello SecondActivity";        //向下传递数据
                //Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                //intent.putExtra("extra_data",data);
                //startActivity(intent);
                
                Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                startActivityForResult(intent,1);
                
            }

使用了startActivityForResult()方法来启动SecodActivity,请求码只要是一个唯一值就可以了,这里传入了1。

我们要在SecondAcitivity中给按钮注册点击事件,并在点击事件中添加返回数据类型的逻辑,代码如下:

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

       // Intent intent = getIntent();
        //String data = intent.getStringExtra("extra_data");
        //Log.d("SecondActivity",data);

        Button button2 = (Button) findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.putExtra("data_return","Hellow FistActivity");
                setResult(RESULT_OK,intent);
                finish();
            }
        });
    }

我们还是构建了一个Intent,只不过这个Intent不仅仅是用来传递数据而已,它没有指定任何的意图,紧接着把要传递的数据存放在Intent中,然后调用了setResult()方法,setResult方法是非常重要的,是专门用来向上一个活动传递数据。setResult()方法接收两个参数,第一个参数是用用于向上一个活动返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED这两个值,第二个参数则把带有数据的Intent传递回去,然后调用finish()方法来销毁当前活动。这样就实现了在销毁当前活动时,把要传递的数据返回给上一个活动。

由于我们是使用startActivityForResult()方法来启动SecondActivity的,在SecondActivity被销毁后会回调上一个活动的onActivityResult()方法,因此我们需要在FirstActivity中重写这个方法来得到这个数据。代码如下:

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode){
            case 1:
                if(resultCode == RESULT_OK){
                    String ReturnedData = data.getStringExtra("data_return");
                    Log.d("FirstActivity",ReturnedData);
                }
                break;
            default:
        }
    }

onActivityResult()方法带有三个参数,第一个参数是requestCode,即我们在启动活动时传入的请求码(来判断数据来源),第二个参数是resultCode(处理结果是否成功),就是我们在返回数据时传入的数据集。第三个参数data,就是我们携带着返回数据的intent。

现在我们又可以运行程序了。

但是当我们不是通过点击SecondActivity的按钮来返回数据,而是通过按下Back键,这样数据是不是没有办法返回了呢?我们可以在SecondActivity中重写onBackPressed()方法,代码如下:

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

按下Back键,就会执行onBackPressed()方法中的代码。


@override处,按下Ctrl + O,就可以出现你重写的方法,你就可以选择你要重写的方法。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值