@Override public void run() { Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "DispatchEventsRunnable"); try { Systrace.endAsyncFlow( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ScheduleDispatchFrameCallback", mHasDispatchScheduledCount); mHasDispatchScheduled = false; mHasDispatchScheduledCount++; Assertions.assertNotNull(mRCTEventEmitter); synchronized (mEventsToDispatchLock) { // We avoid allocating an array and iterator, and "sorting" if we don't need to. // This occurs when the size of mEventsToDispatch is zero or one. if (mEventsToDispatchSize > 1) { Arrays.sort(mEventsToDispatch, 0, mEventsToDispatchSize, EVENT_COMPARATOR); } for (int eventIdx = 0; eventIdx < mEventsToDispatchSize; eventIdx++) { Event event = mEventsToDispatch[eventIdx]; // Event can be null if it has been coalesced into another event. if (event == null) { continue; } Systrace.endAsyncFlow( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, event.getEventName(), event.getUniqueID()); event.dispatch(mRCTEventEmitter); event.dispose(); } clearEventsToDispatch(); mEventCookieToLastEventIdx.clear(); } } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } }
/** * Process events in the queue as they are added. The queue must be synchronized for thread safety * but we must be careful not to block for too long or else new events get blocked from being * added to the queue causing long delays. The design is to process events in batches. This allows * for the most efficient use of computer cycles since much of the time the queue will not be * blocked. * * <p>This method was modified by tap on 6/17/2004 to allow both efficient event processing and * thread safety. Later optimized by msekoranja. */ public void run() { // eventBatch is local and only referenced by a single thread so we // don't have to synchronize it int eventsToProcess = 0; Event[] eventBatch = new Event[0]; while (!_killed) { try { // for performance reasons we don't want to block for too long // synchronize _queue for thread safety // copy all of the new queued events to the local batch and clear _queue synchronized (_queue) { // wait for new requests while (!_killed && _queue.isEmpty()) _queue.wait(); if (!_killed) { eventsToProcess = _queue.size(); // create new instance of batch array only if necessary if (eventsToProcess > eventBatch.length) eventBatch = new Event[eventsToProcess]; // only copy (will not recreate array) _queue.toArray(eventBatch); _queue.clear(); // notify queue clean-up _queue.notifyAll(); } } // process all events in the local batch until it is empty for (int i = 0; !_killed && i < eventsToProcess; i++) { // catch all exceptions, so that one buggy listener does not harm the others final Event event = eventBatch[i]; try { // remove from override id final Object overrideId = eventBatch[i]._overrideId; if (overrideId != null) { synchronized (_overrideMap) { _overrideMap.remove(overrideId); } } event.dispatch(); } catch (Throwable th) { th.printStackTrace(); } decrementSyncCounter(eventBatch[i]); eventBatch[i] = null; // allow to be gc'ed Thread.yield(); } } catch (Throwable th) { th.printStackTrace(); } } }
void remove(Event ev) { m_events.remove(ev); ev.dispatch( new Event.Switch() { private void onObjectEvent(ObjectEvent e) { if (e.equals(getLastEvent(e.getObject()))) { m_objectEvents.remove(getKey(e.getObject())); } } public void onCreate(CreateEvent e) { onObjectEvent(e); } public void onDelete(DeleteEvent e) { onObjectEvent(e); } public void onSet(SetEvent e) { if (e.equals(getLastEvent(e.getObject(), e.getProperty()))) { m_setEvents.remove(getKey(e.getObject(), e.getProperty())); } } private void onCollectionEvent(PropertyEvent e) { List lst = (List) m_collectionEvents.get(getKey(e.getObject(), e.getProperty())); if (lst != null) { lst.remove(e); } } public void onAdd(AddEvent e) { onCollectionEvent(e); } public void onRemove(RemoveEvent e) { onCollectionEvent(e); } }); }
public void add(Event ev) { m_events.add(ev); ev.dispatch( new Event.Switch() { private void onObjectEvent(ObjectEvent e) { m_objectEvents.put(getKey(e.getObject()), e); ObjectType type = m_ssn.getObjectType(e.getObject()); for (Iterator it = type.getProperties().iterator(); it.hasNext(); ) { Property prop = (Property) it.next(); Object key = getKey(e.getObject(), prop); if (prop.isCollection()) { if (m_collectionEvents.containsKey(key)) { m_collectionEvents.remove(key); } } else { if (m_setEvents.containsKey(key)) { m_setEvents.remove(key); } } } } public void onCreate(CreateEvent e) { onObjectEvent(e); } public void onDelete(DeleteEvent e) { Object key = getKey(e.getObject()); boolean found = false; if (m_coalescing && getLastEvent(e.getObject()) != null) { CreateEvent ce = (CreateEvent) getLastEvent(e.getObject()); for (Iterator it = m_events.iterator(); it.hasNext(); ) { Event ev = (Event) it.next(); if (ev.equals(ce)) { found = true; } if (!found) { continue; } if (getKey(ev.getObject()).equals(key)) { it.remove(); } else if (ev instanceof PropertyEvent) { PropertyEvent pe = (PropertyEvent) ev; if (key.equals(getKey(pe.getArgument()))) { it.remove(); } } } if (!found) { throw new IllegalStateException(); } } onObjectEvent(e); if (m_coalescing && found) { m_objectEvents.remove(key); for (int i = m_events.size() - 1; i >= 0; i--) { if (m_events.get(i) instanceof DeleteEvent) { DeleteEvent de = (DeleteEvent) m_events.get(i); if (key.equals(getKey(de.getObject()))) { m_objectEvents.put(key, de); break; } } } } } public void onSet(SetEvent e) { m_setEvents.put((getKey(e.getObject(), e.getProperty())), e); } private void onCollectionEvent(PropertyEvent e) { Object key = getKey(e.getObject(), e.getProperty()); List lst = (List) m_collectionEvents.get(key); if (lst == null) { lst = new LinkedList(); m_collectionEvents.put(key, lst); } lst.add(e); } public void onAdd(AddEvent e) { onCollectionEvent(e); } public void onRemove(RemoveEvent e) { onCollectionEvent(e); } }); }