socket.io событие эмитится слишком много раз

205
14 сентября 2017, 15:43

Задача:

Получить имена пользователей

Проблема:

Для начала я добавляю макеты этих диалогов - первая строчка цикла. Потом я отправляю JSONObject через этот emit (все работает!)

Далее, по логике, должен пройти socket.on, но он очень странно работает. Цикл идет только 4 раза, а лог, который я добавлял внутрь этого socket.on выполнялся куда больше кол-во раз и он находил только одного пользователя. То есть работает бешено и не понятно по какой логике. Может это как-то можно синхронизировать?

for( i= contacts.size()-1; i >= 0; i--){
        data.add(new DialogInfo("null", contacts.get(i), "null", "null", contacts.get(i)));
        for( i= contacts.size()-1; i >= 0; i--){
            try {
                obj.put("id", contacts.get(i));
                socket.emit("info", obj);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            socket.on("user_info", new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    userInfo = (JSONObject) args[0];
                    try {
                        adapter.editItemByID(userInfo.getString("id"), new DialogInfo(userInfo.getString("nick"),
                                userInfo.getString("id"), "null", "null", userInfo.getString("id")));
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

Надеюсь, вы сможете помочь решить мне эту проблему!

Answer 1

При выполнении команды socket.on каждый раз вешается листенер, который не убирает предыдущий. Т.е. после прохождения N раз по циклу будет висеть N листенеров. И они все одновременно будут вызываться по этому событию.

Как вариант решения проблемы, если предыдущие листенеры по этому ивенту не нужны, можно непосредственно перед socket.on("user_info", new Emitter.Listener(){}) делать socket.off("user_info"). Этот метод удалит все листенеры по ивенту "user_info". Так же можно убирать конкретный листенер, по конкретному ивенту, если использовать не анонимный класс листенера, а вполне определенный объект класса, вынесенный в переменную, следующим образом socket.off("user_info", onUserInfoListener)

Так же, для наблюдения за событиями, которые эмитятся, я настоятельно рекомендую использовать логи самой socket.io, вместо ручных логов в листенерах, следующим образом. Вспомогательный класс:

import android.util.Log;
import java.util.logging.*; 
/** 
 * Make JUL work on Android. 
 */ 
public class AndroidLoggingHandler extends Handler { 
    public static void reset(Handler rootHandler) { 
        Logger rootLogger = LogManager.getLogManager().getLogger("");
        Handler[] handlers = rootLogger.getHandlers(); 
        for (Handler handler : handlers) { 
            rootLogger.removeHandler(handler); 
        } 
        rootLogger.addHandler(rootHandler); 
    } 
    @Override 
    public void close() { 
    } 
    @Override 
    public void flush() { 
    } 
    @Override 
    public void publish(LogRecord record) {
        if (!super.isLoggable(record))
            return; 
        String name = record.getLoggerName();
        int maxLength = 30;
        String tag = name.length() > maxLength ? name.substring(name.length() - maxLength) : name;
        try { 
            int level = getAndroidLevel(record.getLevel());
            Log.println(level, tag, record.getMessage());
            if (record.getThrown() != null) {
                Log.println(level, tag, Log.getStackTraceString(record.getThrown()));
            } 
        } catch (RuntimeException e) {
            Log.e("AndroidLoggingHandler", "Error logging message.", e);
        } 
    } 
    static int getAndroidLevel(Level level) {
        int value = level.intValue();
        if (value >= 1000) {
            return Log.ERROR;
        } else if (value >= 900) {
            return Log.WARN;
        } else if (value >= 800) {
            return Log.INFO;
        } else { 
            return Log.DEBUG;
        } 
    } 
} 

Дальше непосредственно в месте применения в активити или фрагменте в onCreate инициализировать след. образом:

@Override 
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    AndroidLoggingHandler.reset(new AndroidLoggingHandler()); 
    java.util.logging.Logger.getLogger("my.category").setLevel(Level.FINEST);
}

В таком случае будет видно реальное количество раз эмита всех событий.

READ ALSO
Не могу нормально разобраться с git openshift

Не могу нормально разобраться с git openshift

Привет! В общем, создал бота для Telegram на javaПришло время деплоя

268
Android WebView. Копирование и вставка текста

Android WebView. Копирование и вставка текста

Используя WebView наткнулся на такой баг, что при долгом нажатии не появляется "менюшка" для работы с текстом(Коп, Встав и ТД)В Google информация...

281
JAVA проверка новых версий

JAVA проверка новых версий

Есть программа написанная на JAVAJar файл обернут Launch4j и сделан инсталятор Inno Setup

221
Кастомный MediaController

Кастомный MediaController

Стандартный контроллер может ставить на паузу и перематыватьНужно добавить кнопку полноэкранного режима и пару других

174