Android页面如何接收参数?

99ANYc3cd6
预计阅读时长 36 分钟
位置: 首页 参数 正文

场景设定

假设我们要从 MainActivity 跳转到 SecondActivity,并传递两个参数:

android 页面接收参数
(图片来源网络,侵删)
  • 一个字符串:"Hello from MainActivity"
  • 一个数字:2025

使用 IntentputExtra() (最常用)

这是最直接、最常用的方法,适用于传递少量、简单的数据类型。

发送方 (MainActivity)

使用 IntentputExtra() 方法将数据附加到 Intent 对象中。

// 在 MainActivity.kt 中
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 1. 创建一个 Intent,指定从当前 Activity 到 SecondActivity
        val intent = Intent(this, SecondActivity::class.java)
        // 2. 使用 putExtra() 方法添加参数
        // 第一个参数是 "键" (key),第二个参数是 "值" (value)
        // 键是字符串,建议使用常量或包名作为前缀,以避免冲突
        intent.putExtra("EXTRA_USER_MESSAGE", "Hello from MainActivity")
        intent.putExtra("EXTRA_USER_ID", 2025)
        // 3. 启动 SecondActivity
        startActivity(intent)
    }
}

接收方 (SecondActivity)

在目标 ActivityonCreate()onNewIntent() 方法中,通过 intent 对象获取数据。

// 在 SecondActivity.kt 中
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.widget.TextView
class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        // 1. 获取启动当前 Activity 的 Intent 对象
        val intent = intent
        // 2. 使用 get...Extra() 方法根据键来获取值
        // 必须提供默认值,以防 Intent 中没有这个键
        val message = intent.getStringExtra("EXTRA_USER_MESSAGE") ?: "No message received"
        val id = intent.getIntExtra("EXTRA_USER_ID", -1) // -1 是默认值
        // 3. 将获取到的数据显示在界面上
        findViewById<TextView>(R.id.tvReceivedData).text = "Message: $message, ID: $id"
    }
}

优点:

android 页面接收参数
(图片来源网络,侵删)
  • 简单直接,易于理解和使用。
  • 适用于所有基本数据类型(String, int, boolean, float, double, char, Bundle 等)。

缺点:

  • 如果传递的数据很多或很复杂,代码会变得臃肿。
  • 类型安全较差,如果键名写错,会在运行时(而不是编译时)导致 NullPointerException

使用 Bundle (更规范)

Bundle 本质上是一个键值对的数据容器,Intent 内部也使用了 Bundle,将数据先放入 Bundle,再将 Bundle 放入 Intent,是一种更结构化的做法。

发送方 (MainActivity)

// 在 MainActivity.kt 中
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 1. 创建一个 Bundle 对象
        val bundle = Bundle()
        // 2. 向 Bundle 中添加数据
        bundle.putString("EXTRA_USER_MESSAGE", "Hello from MainActivity via Bundle")
        bundle.putInt("EXTRA_USER_ID", 2025)
        // 3. 创建 Intent
        val intent = Intent(this, SecondActivity::class.java)
        // 4. 将 Bundle 放入 Intent
        intent.putExtras(bundle)
        // 或者一步到位: intent.putExtras(Bundle().apply { ... })
        startActivity(intent)
    }
}

接收方 (SecondActivity)

接收方代码和方法一完全一样,因为 Intent 会把 Bundle 里的数据“平铺”到自己身上。

// 在 SecondActivity.kt 中
// ... (代码同方法一)
val message = intent.getStringExtra("EXTRA_USER_MESSAGE") ?: "No message received"
val id = intent.getIntExtra("EXTRA_USER_ID", -1)
// ...

优点:

android 页面接收参数
(图片来源网络,侵删)
  • 逻辑更清晰,先将所有数据打包,再统一发送。
  • 方便将数据集一次性传递。

缺点:

  • 对于接收方来说,和使用 putExtra 没有区别,并没有提升类型安全性。

使用 Kotlinby intent() 扩展属性 (推荐,现代 Android 开发最佳实践)

这是 Google 推荐的现代 Android 开发方式,利用了 Kotlin 的属性委托功能,能让你的代码更简洁、更安全。

添加依赖

确保你的项目已经添加了 androidx-activity-ktxandroidx-fragment-ktx 依赖,它们通常在新项目中默认包含。

// 在 app/build.gradle 中
dependencies {
    implementation 'androidx.activity:activity-ktx:1.8.2'
    implementation 'androidx.fragment:fragment-ktx:1.6.2'
    // ... 其他依赖
}

定义接收参数的类

创建一个数据类来封装所有需要传递的参数,这是实现类型安全的关键!

// 在一个单独的文件中,UserActivityParams.kt
package com.example.myapp
data class UserActivityParams(
    val message: String,
    val id: Int
)

发送方 (MainActivity)

代码依然很简单,但我们需要手动创建 Bundle 并放入数据。

// 在 MainActivity.kt 中
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 1. 创建 Bundle 并放入所有参数
        val params = Bundle().apply {
            putString("EXTRA_USER_MESSAGE", "Hello from MainActivity with KTX")
            putInt("EXTRA_USER_ID", 2025)
        }
        // 2. 创建 Intent 并放入 Bundle
        val intent = Intent(this, SecondActivity::class.java).apply {
            putExtras(params)
        }
        startActivity(intent)
    }
}

接收方 (SecondActivity) - 核心步骤

使用 by intent() 委托来自动获取参数。

// 在 SecondActivity.kt 中
import android.os.Bundle
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf // 可选,用于更方便地创建 Bundle
import com.example.myapp.UserActivityParams // 导入我们定义的数据类
class SecondActivity : AppCompatActivity() {
    // 使用 by intent() 委托来自动获取参数
    // 它会尝试从 Intent 中获取键为 "EXTRA_USER_MESSAGE" 的字符串和 "EXTRA_USER_ID" 的整数
    // 并将它们构造成一个 UserActivityParams 对象
    private val params: UserActivityParams by intent()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        // 直接使用 params 对象,它不为 null (除非你在委托中设置了可为 null)
        // 如果参数缺失,默认会抛出 IllegalArgumentException,你可以处理它
        try {
            findViewById<TextView>(R.id.tvReceivedData).text = "Message: ${params.message}, ID: ${params.id}"
        } catch (e: IllegalArgumentException) {
            // 处理参数缺失的情况
            findViewById<TextView>(R.id.tvReceivedData).text = "Error: Missing required parameters."
        }
    }
}

如何实现 by intent() 委托? 你可以自己编写一个委托函数,或者使用第三方库,这里提供一个简单的实现示例:

// 在一个工具类中,ActivityExt.kt
import android.content.Intent
import androidx.activity.ComponentActivity
// 一个简单的委托函数,用于从 Intent 中获取数据并构造成对象
fun <T> ComponentActivity.intent(key: String, creator: (Intent) -> T): Lazy<T> {
    return lazy {
        creator(intent)
    }
}
// 然后在 SecondActivity 中这样使用 (这是更灵活的方式)
// private val params: UserActivityParams by intent { intent ->
//     UserActivityParams(
//         message = intent.getStringExtra("EXTRA_USER_MESSAGE") ?: "",
//         id = intent.getIntExtra("EXTRA_USER_ID", -1)
//     )
// }

虽然手动写委托有点麻烦,但很多项目(如 Hilt)已经提供了类似的功能,关键在于,使用数据类来定义参数,使得代码结构清晰且类型安全。

优点:

  • 类型安全:编译器会检查参数是否存在,而不是在运行时才发现错误。
  • 代码简洁:在接收方,params 对象可以直接使用,无需重复调用 get...Extra()
  • 可读性强:数据类清晰地定义了页面需要哪些参数。
  • 易于维护:增删参数只需修改数据类,影响范围小。

缺点:

  • 需要额外的数据类定义。
  • 对于初学者,委托的概念可能需要一点时间理解。

使用 ViewModel (适用于复杂数据和配置变更)

当页面因屏幕旋转等配置变更而销毁并重建时,Intent 中的数据会丢失,如果数据比较重要,或者需要在 FragmentActivity 之间共享,使用 ViewModel 是最佳选择。

发送方 (MainActivity)

// 在 MainActivity.kt 中
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
class MainActivity : AppCompatActivity() {
    // 获取 ViewModel
    private val sharedViewModel: SharedViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 将数据设置到 ViewModel 中
        sharedViewModel.userData.value = "Hello from MainActivity with ViewModel"
        sharedViewModel.userId.value = 2025
        // 启动 SecondActivity
        startActivity(Intent(this, SecondActivity::class.java))
    }
}

共享的 ViewModel

// 在 SharedViewModel.kt 中
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class SharedViewModel : ViewModel() {
    // 使用 MutableLiveData 来存储可变数据
    val userData = MutableLiveData<String>()
    val userId = MutableLiveData<Int>()
    // 如果需要对外暴露不可变的 LiveData,可以这样
    // val userData: LiveData<String> = _userData
}

接收方 (SecondActivity)

// 在 SecondActivity.kt 中
import android.os.Bundle
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
class SecondActivity : AppCompatActivity() {
    // 获取同一个 SharedViewModel 实例
    private val sharedViewModel: SharedViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        // 观察 LiveData 的变化,当数据变化时更新 UI
        sharedViewModel.userData.observe(this) { message ->
            sharedViewModel.userId.observe(this) { id ->
                findViewById<TextView>(R.id.tvReceivedData).text = "Message: $message, ID: $id"
            }
        }
    }
}

注意:要使用 ViewModel,需要在 AndroidManifest.xml 中为 Activity 添加 android:configChanges="orientation" 属性,或者不添加(让系统重建,ViewModel 会自动保留数据)。

优点:

  • 数据持久化:完美处理屏幕旋转等配置变更,数据不会丢失。
  • 组件间共享:同一个 ViewModel 实例可以在 Activity 和其 Fragment 之间共享数据。

缺点:

  • 对于简单的页面跳转数据传递,有点“杀鸡用牛刀”。
  • 代码量相对较多。

总结与推荐

方法 优点 缺点 适用场景
putExtra() 简单、直接、通用 类型不安全,参数多时臃肿 传递少量、简单的数据,快速原型开发。
Bundle 结构化,便于管理数据集 putExtra 对接收方无区别 需要将多个参数作为一个整体传递时。
Kotlin by intent() 类型安全、代码简洁、可读性强 需要定义数据类,理解委托概念 现代 Android 开发的首选,推荐用于绝大多数场景。
ViewModel 数据持久化,组件间共享 代码量大,略显复杂 需要跨配置变更保留数据,或在 Activity/Fragment 间共享数据。

给新手的建议:

  • putExtra() 开始,它是最基础的知识点。
  • 尽快转向 Kotlin by intent() 的方式,它能让你写出更专业、更健壮的代码,这是行业内的主流做法。
  • 当你遇到屏幕旋转导致数据丢失,或者需要在多个 UI 组件间共享数据时,再学习使用 ViewModel
-- 展开阅读全文 --
头像
minikatz免参数版本如何使用?
« 上一篇 今天
华为Watch 3参数有哪些值得关注的亮点?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

最近发表

标签列表

目录[+]