Страницы

Поиск по вопросам

четверг, 2 января 2020 г.

Не могу возвратить результат из анонимного класса

#java #android


Такая проблема. У меня есть метод

public DriverBadge updateDriverBadges() {
        DriverBadge driverBadge;
        try {
            ServerProxy.GetInstance().GetDriverBadge(new IRemoteCallback() {
                @Override
                public void Callback(Exception ex, DriverBadge badge) throws Exception {
        ...
                    driverBadge = badge;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }


        return driverBadge;
    }


Я вызываю с UI метод, который мне ворачивает результат. В этом методе вызывается
метод с колбеком, в котором этот результат приходит от сервера. проблема в том, что
на вот этом месте driverBadge = badge; компилятор ругается. Как я могу вернуть результат
пришедший в колбеке, своим методом?

Кусок кода, где ошибка:

    


Ответы

Ответ 1



В Java из анонимного класса нельзя вернуть не final-переменные, поэтому в таком виде вам результат в основном классе не получить. Самое простое - сделать класс не анонимным, а, к примеру, внутренним или еще лучше, имплементировать интерфейс (коллбэк) в основной класс и переопределить метод в нем - так вы получите полный доступ к возвращаемым значениям в основном классе, передавая эти значения в поля основного класса. Если же вам нужен непременно анонимный класс, то можно использовать сеттер (метод, устанавливающий значения полям класса) в основном классе, который будет вызываться из анонимного класса и присваивать переданное коллбэком значение в поле основного класса. Можно еще написать некий метод основного класса, который вы будете вызывать из анонимного класса. Он будет принимать в качестве аргументов какие то значения этого анонимного класса и делать с ними определенные действия. PS: из кусочка кода в вопросе нельзя сделать завершенные примеры реализаций сказанного выше, а писать абстрактные примеры "с нуля" мне лень :), так что прошу прощения (может тоскливыми зимними вечерами допишу позже). Вообще, со всеми этими реализациями каждый программист под андроид сталкивается постоянно, когда получает результаты от различных листенеров (слушателей событий), так что с примерами проблем быть не должно.

Ответ 2



Я не знаю, что это за API-метод (по getDriverBadge гуглится только этот ваш вопрос здесь и на en.SO), но если бы он мог сразу вернуть DriverBadge (или кинуть исключение), он бы это сделал. А раз он работает через callback, видимо, он работает асинхронно и может вызвать этот callback значительно позже. Поэтому обновлять локальную переменную (хоть с одноэлементным массивом как у @holodnsk, хоть превратив её в поле) скорее всего небезопасно: возможна ситуация, когда после выхода из вызова GetDriverBadge ваш callback ещё не будет вызван, а вызовется когда-нибудь позже, может даже из другого потока. Это, кстати, объясняет, почему локальную переменную нельзя менять из анонимного класса. Java гарантирует, что все локальные переменные меняются только текущим методом и текущим потоком. Это невероятно крутая гарантия и очень упрощает многопоточное программирование, делая его надёжным. Отказаться от неё нельзя, иначе Java будет не Java. Чтобы разрешить эту проблему, вам нужно пересмотреть в корне подход к решению вашей задачи. Для чего updateDriverBadges() возвращает значение? Чтобы потом нарисовать значок в пользовательском интерфейсе? Так и вызовите обновление пользовательского интерфейса прямо из callback, а метод updateDriverBadges() пусть ничего не возвращает.

Ответ 3



объяви final массив с одним элементом, и обращайся к этому элементу как твоей душе угодно, однако обрати внимание на ответ Tagir Valeev public DriverBadge updateDriverBadges() { final DriverBadge[] driverBadge = new DriverBadge[1]; try { ServerProxy.GetInstance().GetDriverBadge(new IRemoteCallback() { @Override public void Callback(Exception ex, DriverBadge badge) throws Exception { ... driverBadge[0] = badge; } }); } catch (Exception e) { e.printStackTrace(); } return driverBadge; }

Комментариев нет:

Отправить комментарий