You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native Android:从Service向JavaScript发送事件的问题

解决方案

方案1:通过React Native Module持有ReactContext引用

你可以创建一个自定义React Native Module,在初始化时保存ReactApplicationContext的静态引用,之后在Service中直接调用该引用:

  1. 创建自定义Module:
class TimerModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
    companion object {
        @Volatile
        private var reactContext: ReactApplicationContext? = null

        fun getReactContext(): ReactApplicationContext? {
            return reactContext
        }
    }

    override fun getName(): String {
        return "TimerModule"
    }

    override fun initialize() {
        super.initialize()
        reactContext = reactApplicationContext
    }

    override fun onCatalystInstanceDestroy() {
        super.onCatalystInstanceDestroy()
        reactContext = null
    }
}
  1. 在Package中注册这个Module:
class TimerPackage : ReactPackage {
    override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
        return listOf(TimerModule(reactContext))
    }

    override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
        return emptyList()
    }
}
  1. 在Service中使用:
class TimerService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        TimerModule.getReactContext()?.let { context ->
            context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
                .emit("tick", "tock")
        }
        return START_STICKY
    }
}

注意:这种方式要留意内存泄漏问题,必须在Module销毁时清空引用,避免持有ReactContext导致内存无法释放。

方案2:用本地广播解耦Service和React Native

这种方式更解耦,Service不需要直接依赖ReactContext,而是通过本地广播传递事件,由React Native Module接收后转发给JS:

  1. 在Service中发送本地广播:
class TimerService : Service() {
    private val localBroadcastManager by lazy { LocalBroadcastManager.getInstance(this) }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val intent = Intent("TIMER_TICK").apply {
            putExtra("data", "tock")
        }
        localBroadcastManager.sendBroadcast(intent)
        return START_STICKY
    }
}
  1. 在React Native Module中监听广播并转发给JS:
class TimerModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext), BroadcastReceiver {
    private val localBroadcastManager = LocalBroadcastManager.getInstance(reactContext)

    override fun getName(): String {
        return "TimerModule"
    }

    override fun initialize() {
        super.initialize()
        val filter = IntentFilter("TIMER_TICK")
        localBroadcastManager.registerReceiver(this, filter)
    }

    override fun onReceive(context: Context?, intent: Intent?) {
        intent?.getStringExtra("data")?.let { data ->
            reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
                .emit("tick", data)
        }
    }

    override fun onCatalystInstanceDestroy() {
        super.onCatalystInstanceDestroy()
        localBroadcastManager.unregisterReceiver(this)
    }
}

方案3:调整架构,用Headless JS(可选)

如果你的计时器需要在后台运行,也可以考虑使用React Native的Headless JS,它允许你在后台运行JS代码,无需额外的Android Service(底层仍基于Service实现)。这种方式可以让你直接在JS层管理计时器状态,避免原生层的通信问题:

// index.js
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';

const TimerTask = async () => {
  // 在这里处理计时器逻辑,发送事件到前台页面
  // 比如用DeviceEventEmitter发送事件
};

AppRegistry.registerComponent(appName, () => App);
AppRegistry.registerHeadlessTask('TimerTask', () => TimerTask);

然后在原生层启动Headless JS任务:

class TimerService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val reactNativeIntent = Intent(applicationContext, HeadlessJsTaskService::class.java)
        reactNativeIntent.putExtra(HeadlessJsTaskService.EXTRA_TASK_KEY, "TimerTask")
        startService(reactNativeIntent)
        return START_STICKY
    }
}

针对你的实际需求建议

对于健身房组间休息计时器场景:

  • 优先选择方案2(本地广播),解耦原生Service和React Native,降低内存泄漏风险
  • 新增页面时,除了监听tick事件,还可以在页面挂载时通过Module调用原生方法主动请求Service的当前计时器状态,确保页面打开时能显示最新数据

内容的提问来源于stack exchange,提问作者Brandon Presley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 12:30:48