Closed AntiHate closed 8 years ago
Hey antihate, thanks for reporting this issue!
React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
react-native
or for more real time interactions, ask on Discord in the #react-native channel.you can get ReactContext from view's getContext() method.
also you are extending wrong classes. please search for ReactSwitch.java, ReactSwitchEvent.java and ReactSwitchManager.java files.
Thanks @kocyigityunus for the solution, I was doing it all wrong that's because I've no idea about the android native code.
I've solved my problem by using LocalBroadcastManager to send events to NativeModule.
hey,i am working for this alos.can you tell me how to use localBroadcastManager? i want native send event to js and also cant initialise without reactContext
yeap,i am facing the same question. please give me a answer, thanks a lot
Me too, the docs on events is quite cryptic since it assumes you have a ReactContext on hand, but a lot of people seems to have a very hard time sending events from native android to js
last month when i read reactnative source code , i found there was a way to acheve ReactContext.sentEvent; Maybe you should change the way your code had been written.
I post the work around here using LocalBroadcastManager as AntiHate suggested, for those still couldn't find it. The ideal is to have an inner class to listen for events from LocalBroadcastManager.
First we need a native module as usual:
public class SomeNativeModule extends ReactContextBaseJavaModule {
private ReactContext mReactContext;
// instance of our receiver
private LocalBroadcastReceiver mLocalBroadcastReceiver;
public SomeNativeModule(ReactApplicationContext reactContext) {
super(reactContext);
this.mReactContext = reactContext;
this.mLocalBroadcastReceiver = new LocalBroadcastReceiver();
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(reactContext);
localBroadcastManager.registerReceiver(mLocalBroadcastReceiver, new IntentFilter("my-custom-event"));
}
Add inner class (of SomeNativeModule) for receive the custom local broadcast:
public class LocalBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String someData = intent.getStringExtra("my-extra-data");
mReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("JS-Event", someData);
}
}
}
3. In your other android class, fire the custom local broadcast event:
public class SomeService extends IntentService { @Override protected void onHandleIntent(Intent intent) { LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this); Intent customEvent= new Intent("my-custom-event"); customEvent.putExtra("my-extra-data", "that's it"); localBroadcastManager.sendBroadcast(customEvent); } }
@hnvcam how unregister LocalBroadcastManager ?
@hhvm-bot thank you very much, your solution worked for me 👍
@hnvcam worked for me too, thank you !!!
Hi There,
I have tried to implement @hnvcam solution to detect when android location services(GPS) are turned on and off. My application requires that if it is turned off the app needs to go to a different screen. The easiest way to do this instead of polling if Location is on or off is using a broadcast. I copied the code almost exactly, just modifying it with my own event parameters.
The event fires properly and the intended behaviour is perfect! Unfortunately, the second time it is fired I get this in logcat.
W/unknown:React: Calling JS function after bridge has been destroyed.
My javascript implementation is simply
if (Platform.OS === "android") {
DeviceEventEmitter.addListener("gpsChanged", e => {
this.checkLocationEnabled();
});
}
Any thoughts would be appreciated 😭
@willcodes I think probably you forget to remove that listener when componentWillUnmount and that leads to the case that your previous instance of that screen still wired to "gpsChanged" event.
@hnvcam Yep, that was the issue. Figured it out a little after I posted. Thanks for your reply/solution though, was very helpful
Also worked for me. Thanks. but how unregister localBroadcastReceiver?
This is how I registered and unregistered, if anyone's interested:
class AlarmModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
override fun getName(): String {
return "AlarmModule"
}
private val alarmReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(reactContext, "called from test receiver", Toast.LENGTH_SHORT).show()
}
}
@ReactMethod
fun setAlarm(message: String, hour: Int, minute:Int) {
reactApplicationContext.registerReceiver(alarmReceiver, IntentFilter("my-custom-event"))
val alarmIntent = Intent("my-custom-event")
val piAlarm = PendingIntent.getBroadcast(reactApplicationContext, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val am = reactApplicationContext!!.getSystemService(ReactContext.ALARM_SERVICE) as AlarmManager
am.set(AlarmManager.RTC_WAKEUP, 0, piAlarm)
}
@ReactMethod
fun cancelAlarm(){
reactApplicationContext.unregisterReceiver(alarmReceiver)
}
}
Why not just use
public static ReactContext mReactContext; //?
Unless this can be a security issue, I guess this is enough.
@eugenecp
Holding Context
as a static property is a bad pettern in Android, for it can cause memory leaks.
See https://android-developers.googleblog.com/2009/01/avoiding-memory-leaks.html for more details.
I have an android service running in the background which gets location updates periodically. And Im passing the data back to the ReactContextBaseJavaModule through Broadcast Receiver. This doesn't work if the app goes to background (Service is still running). Any idea how do I pass the data ?
@theebi I am not sure, but maybe Headless JS would help you I guess https://facebook.github.io/react-native/docs/headless-js-android.html
here's how I did it in an Service extended class (it will run when the intent defined in android manifest file arrives). may help somebody.
public class MyPushListener extends Service {
@Override
public void onMessageReceived(JSONObject message, JSONObject content){
MainApplication application = (MainApplication) this.getApplication();
ReactNativeHost reactNativeHost = application.getReactNativeHost();
ReactInstanceManager reactInstanceManager = reactNativeHost.getReactInstanceManager();
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext != null) {
WritableNativeArray params = new WritableNativeArray();
params.pushString(message.toString());
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("EVENT_HAS_TRIGGERED", params);
}
}
}
Hai @thg303 , I have written the module as a separate node module any idea how can I access MainApplication from this?
not yet @theebi , It's my first plug-in and I work on it in my spare time.
I know I should't be creating a issue for this but I've already asked this at stackoverflow, didn't got any answer yet.
I'm trying to add android native module to send events to JS. I'm using a library which trigger events in native class. I need to send those events back to JS.
Can I get access to ReactContext in OtherClass? or any other way to accomplish this? Any help would be much appreciated.