32.数据传递✅

1.简述

Android开发中,有很多需要数据传递的地方,比如ActivityA->ActivityB->ActivityC, 或fragment传递数据给依附的Activity等,Android中提供了很多传递数据的方式,例如Handler、LiveData、ShareFlow、registerForActivityResult、EventBus等。

先说结论:Flow 最适配kotlin

下面对上述方式做个比较,并给出各种方式的优缺点和demo

1.1.🔍总览对比表

对比表

1.2.🔧各机制使用场景与优缺点

🟩 Handler

用途:
• 主线程 UI 更新(以前)
• 延迟执行、定时器
• 多线程通信(主线程与子线程)

优点:
• 适合与 Looper/MessageQueue 配合,灵活

缺点:
• 不具备生命周期感知,容易内存泄漏
• API 冗长,写法复杂
• 现代项目不推荐直接使用

🟩 LiveData

用途:
• ViewModel → UI 数据绑定
• 生命周期感知型 UI 更新
• 配合 Jetpack MVVM 使用

优点:
• 自动感知生命周期,防止泄漏
• 简单易用
• 支持粘性事件(默认发送最后一个值)

缺点:
• 不支持背压 / 多值广播
• 不适合全局广播事件
• 单活跃订阅者模型,复杂场景受限

🟩 SharedFlow

用途:
• 全局事件通知(替代 EventBus)
• ViewModel 发出一次性事件(如 Toast、跳转等)
• 多页面通信(ActivityA ← ActivityC)

优点:
• 支持多订阅者、高并发、安全
• 线程安全、生命周期可配合协程控制
• 替代 LiveData & EventBus 的首选

缺点:
• 不具备生命周期感知(需 repeatOnLifecycle)
• 协程基础要求较高

🟩 registerForActivityResult

用途:
• 启动系统或自定义页面并接收回调结果(例如:拍照、选择文件、跳转设置页)

优点:
• 生命周期安全
• 解耦清晰,替代 onActivityResult 旧方式
• 简洁直观

缺点:
• 仅适合 Activity → Activity 或 Fragment → Fragment 回调
• 仅用于 startActivityForResult 替代场景

🟩 EventBus(如 greenrobot)

用途:
• 广播全局事件通知(登录成功、退出等)
• 组件间通信

优点:
• 简单快速、上手容易
• 解耦明显

缺点:
• 滥用风险高、全局监听容易混乱
• 不具备生命周期感知,容易泄漏
• 调试难度大,不推荐在现代架构中使用

2.Flow+viewmodel实例

📦 示例目录结构(简化)

MyActivity.kt         <-- UI 层
MyViewModel.kt        <-- ViewModel 层
UiState.kt            <-- 数据状态模型

🧩 1. UiState.kt

data class UiState(
    val loading: Boolean = false,
    val content: String? = null,
    val error: String? = null
)

🧠 2. MyViewModel.kt

class MyViewModel : ViewModel() {

    // StateFlow - 页面状态
    private val _uiState = MutableStateFlow(UiState())
    val uiState: StateFlow<UiState> = _uiState

    // SharedFlow - 一次性事件(如 Toast)
    private val _toastEvent = MutableSharedFlow<String>()
    val toastEvent: SharedFlow<String> = _toastEvent

    fun loadData() {
        viewModelScope.launch {
            _uiState.value = UiState(loading = true)
            delay(1000) // 模拟网络请求
            val success = Random.nextBoolean()
            if (success) {
                _uiState.value = UiState(loading = false, content = "加载成功!")
                _toastEvent.emit("数据加载完成")
            } else {
                _uiState.value = UiState(loading = false, error = "加载失败")
                _toastEvent.emit("加载失败,请重试")
            }
        }
    }
}

🖥️ 3. MyActivity.kt

class MyActivity : AppCompatActivity() {

    private val viewModel by viewModels<MyViewModel>()

    private lateinit var textView: TextView
    private lateinit var progressBar: ProgressBar
    private lateinit var retryButton: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_my)

        textView = findViewById(R.id.textView)
        progressBar = findViewById(R.id.progressBar)
        retryButton = findViewById(R.id.retryButton)

        retryButton.setOnClickListener {
            viewModel.loadData()
        }

        // 生命周期感知地收集 Flow
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                launch {
                    viewModel.uiState.collect { state ->
                        progressBar.visibility = if (state.loading) View.VISIBLE else View.GONE
                        textView.text = state.content ?: state.error ?: "暂无内容"
                        retryButton.visibility = if (state.error != null) View.VISIBLE else View.GONE
                    }
                }
                launch {
                    viewModel.toastEvent.collect { message ->
                        Toast.makeText(this@MyActivity, message, Toast.LENGTH_SHORT).show()
                    }
                }
            }
        }

        viewModel.loadData() // 首次加载
    }
}

🧱 4. activity_my.xml(布局文件)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:padding="16dp"
    android:gravity="center"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        android:id="@+id/progressBar"
        android:visibility="gone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/textView"
        android:text="加载中..."
        android:textSize="18sp"
        android:padding="16dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/retryButton"
        android:visibility="gone"
        android:text="重试"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>
总结
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容