Android应用开发:Activity(2)

目录

5、使用 Intent 在 Activity 之间穿梭

(1)使用显式 Intent

(2)使用隐式Intent

(3)更多隐式 Intent 的用法

(4)向下一个 Activity 传递数据

(5)返回数据给上一个 Activity


5、使用 Intent 在 Activity 之间穿梭

        IntentAndroid程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同的组件传递数据Intent一般用于启动Activity,启动Service以及发送广播等场景Intent有多个构造函数的重载。Intent大致可以分为两种:显示Intent和隐式Intent。

(1)使用显式 Intent

① 右击com.example.activitytest包 -> New -> Activity -> Empty Activity -> 命名SecondActivity -> 勾选Generate Layout File -> 给布局文件命名,但不要勾选Launcher Activity选项

② 修改布局文件 activity_second.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/button2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Button 2" />

</LinearLayout>

③ 任何一个 Activity 都是需要在 AndroidMainfest.xml 中注册的,打开 AndroidMainfest.xml ,Android Studio 已经帮我们自动完成了。因为 SecondActivity 不是主 Activity,因此不需要配置<intent-filter>标签里的内容。

        <activity
            android:name=".SecondActivity"
            android:exported="false" />
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="This is MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        SecondActivity自动添加代码,在Activity加载布局,SetContentView(R.layout.activity_second),AndroidMainfest.xml自动注册布局。

④ 修改 SecondActivity中按钮的点击事件,点击按钮就会跳转到 SecondActivity

        button1.setOnClickListener {
            Toast.makeText(this,"You clicked Button 1",Toast.LENGTH_SHORT).show()
            // 显式Intent
            //第一个参数:启动Activity的上下文
            //第二个参数,指定想要启动的目标Activity
            val intent = Intent(this,SecondActivity::class.java)
            startActivity(intent)
        }

⑤ 运行,点击 Button 1,跳转到 SecondActivity,按一下 Back 键就可以销毁当前 Activity,从而回到上一个 Activity。

(2)使用隐式Intent

        它并不明确指出想要启动哪一个Activity,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并且班我们找出合适的Activity(可以响应这个隐式Intent的Activity)去启动。

        通过在<activity>标签下配置<intent-filter>内容,可能指定当前Activity能够响应的action和category,打开AndroidMainfest.xml,添加下列代码。只有<action>和<category>中的内容同时匹配Intent中指定的action和category时,这个Activity才能响应该Intent

        <activity
            android:name=".SecondActivity"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.example.activitytest.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
button1.setOnClickListener {
    val intent = Intent("com.example.activitytest.ACTION_START")
    startActivity(intent)
}

        android.intent.category.DEFAULT 是一种默认的 category,在调用startActivity( )方法的时候就会自动将这个category 添加到 Intent 中。每个Intent 中只能指定一个action,但能指定多个category。

        再增加一个 category:

button1.setOnClickListener {
    val intent = Intent("com.example.activitytest.ACTION_START")

  	// 调用Intent中的 addCategory() 方法来添加一个自定义的 category

  	intent.addCategory("com.example.activitytest.MY_CATEGORY")
    startActivity(intent)
}

        修改AndroidMainfest.xml

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

        重新运行程序,MainActivity 的界面点击一下按钮,就能成功启动 SecondActivity了。

(3)更多隐式 Intent 的用法

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

        比如,调用系统的浏览器打开需要的网页:

button1.setOnClickListener { 
    val intent = Intent(Intent.ACTION_VIEW)
    intent.data = Uri.parse("https://www.baidu.com")
    startActivity(intent)
}

        

        指定 Intent 的 action 是 Intent.ACTION_VIEW,这是一个 Android 系统内置的动作,其常量值为 android.intent.action.VIEW。然后通过 Uri.parse( ) 方法将一个网址字符串解析成一个Uri 对象, 再调用 Intent 的 setData( ) 方法将这个 Uri 对象传递进去。

        我们还可以在<intent-filter>标签中再配置一个<data>标签,用于更精确地指定当前 Activity 能够响应的数据。 <data>标签中主要可以配置以下内容。

  • android:scheme。用于指定数据的协议部分,如上例中的 https 部分。
  • android:host。用于指定数据的主机名部分,如上例中的 www.baidu.com
  • android:port。用于指定数据的端口部分,一般紧随在主机名之后。
  • android:path。用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容,
  • android:mimeType。用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。

        只有当<data>标签中指定的内容和 Intent 中携带的 Data 完全一致时,当前 Activity 才能够响应该 Intent。在<data>标签中一般不会指定过多的内容。

        比如打开网页只需要指定 android:scheme 为 https,就可以响应所以 https 协议的 Intent。

        ① 创建 ThirdActivity,给布局文件命名为 third_layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ThirdActivity">
    
    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 3"/>

</LinearLayout>

        ② 在 AndroidManifest.xml 中修改 ThirdActivity 的注册信息

<activity
    android:name=".ThirdActivity"
    android:exported="false"
    tools:ignore="AppLinkUrlError">
    <intent-filter >
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="https"/>
   </intent-filter>
</activity>

        我们通过android:scheme 指定了数据的协议必须是 https 协议,这样 ThirdActivity 应该就和浏览器一样,能够响应一个打开网页的 Intent。

另外由于 Android Studio 认为所有能够响应 ACTION_VIEW 的 Activity 都应该加上 BROWSABLE 的 category ,否则就会给出一段警告提醒。加上 BROWSABLE 的 category 是为了实现 deep link 功能,和我们目前学习的东西无关,所以直接使用 tools:ignore 属性将警告忽略即可。

        ③ 运行程序,点击 MainActivity 上的按钮。

        系统自动弹出了一个列表,显示目前能够响应这个 Intent 的所有程序。选择 Chrome 还会像之前一样打开浏览器,并显示百度主页,而如果选择了 ActivityTest,则会启动 ThirdActivity。虽然我们声明了 ThirdActivity 是可以响应打开网页的 Intent 的,但实际上这个 Activity 并没有加载并显示网页的功能。

        除了 https 协议外,我们还可以指定很多其他协议,比如 geo 表示地理位置、tel 表示拨打电话。下面的代码展示了如何在程序中调用系统拨号界面。

button1.setOnClickListener {
    // Intent.ACTION_DIAL  Android 系统的内置动作
    val intent = Intent(Intent.ACTION_DIAL)
    intent.data = Uri.parse("tel:10086")
    startActivity(intent)
}

(4)向下一个 Activity 传递数据

        Intent 在启动 Activity 的时候还可以传递数据,Intent 中提供了一系列 putExtra( ) 方法的重载,可以把想要传递的数据暂存在 Intent 中,在启动另一个 Activity 后,只需要把这些数据从 Intent 中取出就可以了。

        比如,MainActivity 中有一个字符串,把它传到 SecondActivity 中,

① 修改 MainActivity 中 button1的点击事件

button1.setOnClickListener {
    val data = "Hello SecondActivity"
    val intent = Intent(this,SecondActivity::class.java)
    intent.putExtra("extra_data",data)
    startActivity(intent)
}

        putExtra( ) 方法接受两个参数,第一个参数是键,用于之后从 Intent 中取值,第二个参数才是真正要传递的数据。

② 在 SecondActivity 中将传递的数据取出来,并打印出来

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        
        val extraData = intent.getStringExtra("extra_data")
        Log.d("SecondActivity","extra data is $extraData")
    }
}

        上述代码中的 intent 实际上调用的是父类的 getIntent( )方法,获取用于启动 SecondActivity 的 Intent,然后调用 getStringExtra( ) 方法并传入相应的键值,就可以得到传递的数据。如果传递的是整型数据,则使用 getIntExtra( ) 方法;如果传递的是布尔型数据,则使用 getBooleanExtra( ) 方法,以此类推。

        

③ 重新运行程序,在 MaintActivity 的界面点击一下按钮会跳转到 SecondActivity ,查看 Logcat 打印信息。

(5)返回数据给上一个 Activity

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

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

① 修改 MainActivity 中按钮的点击事件

button1.setOnClickListener {
    val intent = Intent(this,SecondActivity::class.java)
    startActivityForResult(intent,1)
}

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

② 在 SecondActivity 中给按钮注册点击事件,并在点击事件中添加返回数据的逻辑

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        button2.setOnClickListener { 
            val intent = Intent()
            intent.putExtra("data_return","Hello MainActivity")
            setResult(RESULT_OK,intent)
            finish()
        }
    }
}

        构建的Intent 仅仅用于传输数据,没有任何”意图“。把要传递的数据存在在 Intent 中,然后调用 setResult( ) 方法。这个方法专门用于向上一个 Activity 返回数据。setResult( ) 方法接受两个参数:第一个参数用于向上一个 Activity 返回处理结果,一般只使用 RESULT_OK 或 RESULT_CANCELED 这两个值;第二个参数则把带有数据的 Intent 传递回去。最后调用 finish( ) 方法来销毁当前 Activity 。

③ 重写onActivityResult( )方法来得到返回的数据

        使用 startActivityForResult( ) 方法来启动 SecondActivity,在 SecondActivity 被销毁之后会回调上一个 Activity 的 onActivityResult( )方法,因此我们需要在 MainActivity 中重写这个方法来得到返回的数据。

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when(requestCode){
            1 -> if(requestCode == RESULT_OK){
                val resultData = data?.getStringExtra("data_return")
                Log.d("FirstActivity","returned data is $resultData")
            }
        }
    }

        onActivityResult( ) 有三个参数:第一个参数 requestCode,即启动 Activity 时的请求码;第二个参数 resultCode,即我们在返回数据时传入的处理结果;第三个参数 data ,即携带着返回数据的 Intent。

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

④ 重新运行程序,点击 Button1

        如果不是通过按钮返回数据,而是通过按下 Back 键回到 MainActivity,可以通过在 SecondActivity 中重写 onBackPressed( ) 方法。

override fun onBackPressed(){
    val intent = Intent()
    intent.putExtra("data_return","Hello MainActivity")
    setResult(RESULT_OK,intent)
    finish()
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值