/**
   * Combines and returns queued messages combined into a single string. Combines as many messages
   * as possible, while staying under MAX_PAYLOAD_SIZE. Returns null if the queue is empty.
   */
  public String popAndEncode(boolean fromOnlineEvent) {
    synchronized (this) {
      registeredListeners[activeListenerIndex].notifyOfFlush(fromOnlineEvent);
      if (queue.isEmpty()) {
        return null;
      }
      int totalPayloadLen = 0;
      int numMessagesToSend = 0;
      for (JsMessage message : queue) {
        int messageSize = calculatePackedMessageLength(message);
        if (numMessagesToSend > 0
            && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE
            && MAX_PAYLOAD_SIZE > 0) {
          break;
        }
        totalPayloadLen += messageSize;
        numMessagesToSend += 1;
      }

      StringBuilder sb = new StringBuilder(totalPayloadLen);
      for (int i = 0; i < numMessagesToSend; ++i) {
        JsMessage message = queue.removeFirst();
        packMessage(message, sb);
      }

      if (!queue.isEmpty()) {
        // Attach a char to indicate that there are more messages pending.
        sb.append('*');
      }
      String ret = sb.toString();
      return ret;
    }
  }