Kotlin中如何通过Intent从BroadcastReceiver向Fragment传递步数数据
我需要在后台及APP关闭时追踪步数,因此创建了两个BroadcastReceiver:一个用于后台通知显示步数,另一个用于更新Fragment UI(会在Fragment销毁时注销)。以下是后者的实现流程:
步骤1:Foreground Service发送步数广播
Intent().also { intent -> intent.setAction(ACTION_STEP_COUNTER_NOTIFICATION) intent.putExtra("stepCount", "$todayTotalStepCount") sendBroadcast(intent) }
步骤2:BroadcastReceiver接收广播并尝试传递给Fragment
open class StepCountBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { super.onReceive(context, intent) if(intent!!.action == ACTION_STEP_COUNTER_NOTIFICATION) { var intent = Intent() var stepCount = intent.getStringExtra("stepCount") var sendMyDiary = Intent(context!!, MyDiaryFragment::class.java) sendMyDiary.putExtra("stepCount", stepCount) context.startActivity(sendMyDiary) } } }
步骤3:Fragment中注册BroadcastReceiver
private val stepCountBroadcastReceiver: BroadcastReceiver = StepCountBroadcastReceiver() val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply { addAction(ACTION_STEP_COUNTER_NOTIFICATION) } LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(stepCountBroadcastReceiver, filter)
我的疑问
每次BroadcastReceiver被调用时,我不知道如何在Fragment中获取传来的stepCount。是否只需添加如下代码即可?
var stepCount = requireActivity().intent.getStringExtra("stepCount")
也就是改成:
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply { addAction(ACTION_STEP_COUNTER_NOTIFICATION) } LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(stepCountBroadcastReceiver, filter) var stepCount = requireActivity().intent.getStringExtra("stepCount")
解答
你的写法存在几个关键问题,直接添加那段代码无法获取到步数数据,正确的实现方式如下:
修复BroadcastReceiver的逻辑错误
原Receiver代码里重新创建了空的Intent,导致无法获取广播传来的步数数据;同时用startActivity启动Fragment的做法完全错误——Fragment不能作为独立组件通过startActivity启动,它必须依附于Activity。正确的做法是让Receiver直接在Fragment内部处理数据更新,不需要单独定义Receiver类,而是在Fragment中创建匿名Receiver。
修改Fragment的Receiver注册与数据处理
在Fragment的onCreate中定义并注册Receiver,直接在onReceive方法中获取步数并更新UI:// 定义匿名Receiver,直接关联Fragment的UI更新 private val stepCountBroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { intent?.takeIf { it.action == ACTION_STEP_COUNTER_NOTIFICATION }?.let { // 从广播Intent中直接获取步数 val stepCount = it.getStringExtra("stepCount") // 在这里更新Fragment的UI,比如更新TextView // stepCountTextView.text = stepCount } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 注册Receiver,若不需要监听网络变化,可去掉ConnectivityManager.CONNECTIVITY_ACTION val filter = IntentFilter().apply { addAction(ACTION_STEP_COUNTER_NOTIFICATION) } LocalBroadcastManager.getInstance(requireActivity()) .registerReceiver(stepCountBroadcastReceiver, filter) } // 记得在Fragment销毁时注销Receiver,避免内存泄漏 override fun onDestroy() { super.onDestroy() LocalBroadcastManager.getInstance(requireActivity()) .unregisterReceiver(stepCountBroadcastReceiver) }同步Foreground Service的广播发送方式
因为Fragment用LocalBroadcastManager注册Receiver,所以Service中也需要用LocalBroadcastManager发送广播,确保能被接收:LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(ACTION_STEP_COUNTER_NOTIFICATION).apply { putExtra("stepCount", "$todayTotalStepCount") })
关键说明
- 不要通过
requireActivity().intent获取广播数据:Activity的启动Intent和广播传递的Intent是完全独立的,广播触发时不会更新Activity的Intent,所以这种方式根本拿不到数据。 - 必须在
onReceive方法中直接从广播Intent里提取数据,然后直接更新Fragment的UI,这是最直接且正确的方式。
内容的提问来源于stack exchange,提问作者Hyejung

