Как можно использовать callback-и из JavaScript в Kotlin в React Native для многократного вызова?

Как можно передать методы из JavaScript в Kotlin для выполнения каждый раз, когда происходит определенное событие, если callback в Kotlin можно вызвать только один раз?
  • 4 февраля 2024 г. 12:48
Ответы на вопрос 2
В React Native, когда вы используете Kotlin в качестве языка для разработки нативных модулей, вы можете столкнуться с ситуацией, когда вам нужно вызывать JavaScript callback несколько раз. Однако, как вы правильно заметили, callback, который передается через границу JS/нативного кода, по умолчанию можно использовать только один раз. Чтобы обойти это ограничение, вы можете использовать EventEmitter.

Давайте рассмотрим шаги, необходимые для создания EventEmitter в Kotlin и его использования в React Native:

1. Создайте класс EventEmitter в Kotlin.

```kotlin
package com.yourapp

import com.facebook.react.modules.core.DeviceEventManagerModule
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.WritableMap
import com.facebook.react.bridge.Arguments

class EventEmitter(private val reactContext: ReactContext) {
    fun sendEvent(eventName: String, params: WritableMap?) {
        reactContext
            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
            .emit(eventName, params)
    }
}
```

2. Используйте EventEmitter в вашем нативном модуле. Создайте метод, который будет принимать callback или Promise и вместо его вызова, отправьте событие через EventEmitter.

```kotlin
class YourNativeModule(private val reactContext: ReactContext): ReactContextBaseJavaModule(reactContext) {

    private val eventEmitter by lazy { EventEmitter(reactContext) }

    @ReactMethod
    fun subscribeToEvent() {
        // Подпишитесь на событие или выполните некоторую асинхронную операцию
        // и используйте eventEmitter для отправки событий в JavaScript.
    }

    private fun onEventHappened() {
        val params = Arguments.createMap().apply {
            putString("eventKey", "eventValue")
        }
        eventEmitter.sendEvent("eventName", params)
    }
}
```

3. Отправляйте события из Kotlin в JavaScript каждый раз, когда это необходимо.

4. В JavaScript подписывайтесь на ваше событие:

```javascript
import { NativeEventEmitter, NativeModules } from 'react-native';

const { YourNativeModule } = NativeModules;
const yourNativeModuleEventEmitter = new NativeEventEmitter(YourNativeModule);

const subscription = yourNativeModuleEventEmitter.addListener(
  'eventName',
  (event) => {
    console.log(event.eventKey); // Обработайте событие
  }
);

// Не забудьте отписаться от события, когда оно больше не нужно
// Например, в componentWillUnmount или в useEffect cleanup
subscription.remove();
```

5. Вызывайте `YourNativeModule.subscribeToEvent()` из JavaScript, чтобы начать получать события.

Используя этот подход, вы сможете отправлять события из Kotlin в JavaScript столько раз, сколько это необходимо. Главное не забывайте управлять подписками и корректно освобождать ресурсы, чтобы избежать утечек памяти.
Наверное вместо 
fun listener(): DeviceListener {
return object: AbstractDeviceListener() {
override public fun onStatusChange(status: String, timestamp: Long) {
statusCallback?.invoke(status)
}
// ...
}
}

вот это

val listener = object : AbstractDeviceListener() {
override public fun onStatusChange(status: String, timestamp: Long) {
statusCallback?.invoke(status)
}
// ...
}
Похожие вопросы