Skip to content

Commit 4dc22f7

Browse files
committed
android: fix events in queue dispatched before listener registered
1 parent 6767bc3 commit 4dc22f7

File tree

3 files changed

+62
-44
lines changed

3 files changed

+62
-44
lines changed

android/src/main/java/com/batch/batch_rn/RNBatchEventDispatcher.java

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import com.batch.android.BatchEventDispatcher;
1010
import com.batch.android.BatchPushPayload;
1111
import com.facebook.react.bridge.Arguments;
12-
import com.facebook.react.bridge.LifecycleEventListener;
1312
import com.facebook.react.bridge.ReactApplicationContext;
1413
import com.facebook.react.bridge.WritableMap;
1514
import com.facebook.react.modules.core.DeviceEventManagerModule;
@@ -21,6 +20,12 @@
2120
*/
2221
public class RNBatchEventDispatcher implements BatchEventDispatcher {
2322

23+
24+
/**
25+
* Max number of events we keep in the event queue
26+
*/
27+
private static final int MAX_QUEUE_SIZE = 5;
28+
2429
/**
2530
* React Context
2631
*/
@@ -36,12 +41,21 @@ public class RNBatchEventDispatcher implements BatchEventDispatcher {
3641
@NonNull
3742
private final LinkedList<RNBatchEvent> events = new LinkedList<>();
3843

44+
/**
45+
* Whether we have a listener registered
46+
* Default: false
47+
*/
48+
private boolean hasListener;
49+
3950
/**
4051
* Send event to the JS bridge
4152
* @param event dispatched event
4253
*/
4354
private void sendEvent(@NonNull RNBatchEvent event) {
4455
if (reactContext == null || !reactContext.hasActiveCatalystInstance()) {
56+
Log.d(RNBatchModule.LOGGER_TAG,
57+
"Trying to send an event while react context is null" +
58+
" or has no active catalyst instance. Aborting.");
4559
return;
4660
}
4761
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
@@ -70,61 +84,69 @@ public void dispatchEvent(@NonNull Batch.EventDispatcher.Type type,
7084
}
7185

7286
RNBatchEvent event = new RNBatchEvent(eventName, params);
73-
synchronized (events) {
74-
events.add(event);
75-
}
76-
77-
if (reactContext == null || !reactContext.hasActiveCatalystInstance()) {
87+
if (!isModuleReady() || !hasListener) {
7888
Log.d(RNBatchModule.LOGGER_TAG,
79-
"React context is null or has no active catalyst instance. Queuing event.");
89+
"Module is not ready or no listener registered yet. Queuing event: ".concat(eventName));
90+
queueEvent(event);
8091
return;
8192
}
82-
dequeueEvents();
93+
sendEvent(event);
8394
}
8495
}
8596

8697
/**
8798
* Dequeue the stored events
8899
*/
89-
public void dequeueEvents() {
90-
if (events.isEmpty()) {
91-
return;
92-
}
100+
private void dequeueEvents() {
93101
synchronized(events) {
94-
sendEvent(events.pop());
102+
if (events.isEmpty()) {
103+
return;
104+
}
105+
while(events.size() != 0) {
106+
sendEvent(events.pop());
107+
}
95108
}
96-
dequeueEvents();
97109
}
98110

99111
/**
100-
* Set the react context instance
101-
*
102-
* Note: We are using a LifecycleEventListener to be notified when the react context
103-
* has a catalyst instance ready
112+
* Put event in queue
113+
* @param event event to queue
114+
*/
115+
private void queueEvent(RNBatchEvent event) {
116+
synchronized (events) {
117+
if(events.size() >= MAX_QUEUE_SIZE) {
118+
events.clear();
119+
}
120+
events.add(event);
121+
}
122+
}
123+
124+
/**
125+
* Set the react context instance used to emit event
104126
* @param reactContext context
105127
*/
106-
public void setReactContext(final ReactApplicationContext reactContext) {
128+
public void setReactContext(@NonNull ReactApplicationContext reactContext) {
107129
this.reactContext = reactContext;
108-
this.reactContext.addLifecycleEventListener(new LifecycleEventListener() {
109-
@Override
110-
public void onHostResume() {
111-
// No we should have a catalyst instance ready
112-
if (reactContext.hasActiveCatalystInstance()) {
113-
dequeueEvents();
114-
reactContext.removeLifecycleEventListener(this);
115-
}
116-
}
130+
}
117131

118-
@Override
119-
public void onHostPause() {
120-
// do noting
121-
}
132+
/**
133+
* Simple method to know if module is ready
134+
* Meaning we have a react context and a catalyst instance ready
135+
* @return true if ready
136+
*/
137+
private boolean isModuleReady() {
138+
return reactContext != null && reactContext.hasActiveCatalystInstance();
139+
}
122140

123-
@Override
124-
public void onHostDestroy() {
125-
// do noting
126-
}
127-
});
141+
/**
142+
* Indicate we have at least one registered listener
143+
* @param hasListener if we have a listener registered
144+
*/
145+
public void setHasListener(boolean hasListener) {
146+
if(!this.hasListener && hasListener) {
147+
this.dequeueEvents();
148+
}
149+
this.hasListener = hasListener;
128150
}
129151

130152
/**

android/src/main/java/com/batch/batch_rn/RNBatchModule.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,11 @@ public void optOutAndWipeData(Promise promise) {
146146

147147
@ReactMethod
148148
public void addListener(String eventName) {
149-
// iOS only
149+
eventDispatcher.setHasListener(true);
150150
}
151151

152152
@ReactMethod
153153
public void removeListeners(double count) {
154-
// iOS only
155154
}
156155

157156
// PUSH MODULE

src/BatchEventEmitter.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
import { DeviceEventEmitter, NativeEventEmitter, NativeModules, Platform } from 'react-native';
1+
import { NativeEventEmitter, NativeModules } from 'react-native';
22

3-
export const BatchEventEmitter = Platform.select({
4-
ios: new NativeEventEmitter(NativeModules.RNBatch),
5-
android: DeviceEventEmitter, // don't use NativeEventEmitter on android to support RN < 0.65
6-
});
3+
export const BatchEventEmitter = new NativeEventEmitter(NativeModules.RNBatch);
74

85
export interface EmitterSubscription {
96
remove: () => void;

0 commit comments

Comments
 (0)