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>