Получить результат метода, полученного в обратном вызове анонимного внутреннего класса?

У меня есть небольшой вопрос здесь.

private boolean isSomethingTrue(String param) {
    boolean result = false;
    myService.hasAlerts(param,new Callback<Boolean>(
        @Override
        public void onSuccess(Boolean hasAlerts) {
            result = hasAlerts;
        }
    });
    return result;
}

В этом коде, как я могу вернуть логическое значение hasAlerts, полученное в обратном вызове? Это не работает, потому что переменная результата не является окончательной. Но когда он окончательный, его нельзя изменить, так что...

Я сделал что-то вроде этого:

private boolean isSomethingTrue(String param) {
    class ResultHolder {
        boolean result=false;
    }
    final ResultHolder resultHolder = new ResultHolder();
    myService.findBoolean(param,new Callback<Boolean>(
        @Override
        public void onSuccess(Boolean hasAlerts) {
            resultHolder.result = hasAlerts;
        }
    });
    return resultHolder.result;
}

Но есть ли более простое решение для такого случая?

Я обнаружил эту проблему при попытке вызвать службу GWT RPC.


person Sebastien Lorber    schedule 13.07.2012    source источник
comment
Ваша логика не работает. Причина в том, что результат возвращается до того, как метод onSuccess() будет выполнен, так как функция асинхронная.   -  person Ganesh Kumar    schedule 13.07.2012
comment
@GaneshKumar - Похоже, hasAlerts не асинхронный. Он вызывает onSuccess перед возвратом.   -  person David Harkness    schedule 13.07.2012
comment
Да, в этом случае метод является синхронным. Иначе не было бы смысла   -  person Sebastien Lorber    schedule 13.07.2012


Ответы (2)


Я могу придумать несколько вариантов — ни один из них особенно захватывающим. Вы можете объединить держатель результата и обратный вызов в один класс и сделать его статическим, если вы можете использовать его в другом месте, но на самом деле это не улучшение.

private boolean isSomethingTrue(String param) {
    class MyCallback implements Callback<Boolean> {
        boolean result = false;
        @Override
        public void onSuccess(Boolean hasAlerts) {
            result = hasAlerts;
        }
    }
    final MyCallback callback = new MyCallback();
    myService.findBoolean(param, callback);
    return callback.result;
}

Вы можете реализовать общий синхронный Future, но это может ввести в заблуждение.

Наконец, если вы делаете это часто, вы можете обобщить держатель значения.

public class Result<T> {
    private T value;
    public void set(T value) { this.value = value; }
    public T get() { return value; }
}

private boolean isSomethingTrue(String param) {
    final Result<Boolean> result = new Result<Boolean>();
    myService.findBoolean(param,new Callback<Boolean>(
        @Override
        public void onSuccess(Boolean hasAlerts) {
            result.set(hasAlerts);
        }
    });
    return result.get();
}
person David Harkness    schedule 13.07.2012

Что вам нужно, так это синхронный RPC. См. >здесь‹ и >здесь‹ для подробностей.

Но я бы предпочел изменить ваш стиль кодирования (при условии, что у вас есть доступ к коду, вызывающему isSomethingTrue()). Предположим, у вас есть такой код, который вызывает ваш метод isSomethingTrue:

if(isSomethingTrue("foo")) {
    doSomeCoolStuff();
}

Вы можете преобразовать это в стиль асинхронного кодирования, изменив его на что-то вроде этого:

isSomethingTrue("foo", new Callback<Boolean>(
    @Override
    public void onSuccess(Boolean result) {
        if(result) {
            doSomeCoolStuff();
        }
    }
});

и

private void isSomethingTrue(String param, Callback callback) {
    myService.hasAlerts(param,callback);
}
person Community    schedule 14.07.2012
comment
Спасибо, кажется хорошей идеей, так как мой метод здесь, чтобы узнать, должен ли я отображать кнопку GWT. Таким образом, я думаю, что могу добавить код, который создает кнопку, непосредственно в обратном вызове, поскольку я добавляю кнопку в глобальную переменную. - person Sebastien Lorber; 14.07.2012