@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);
          }
        });
  }