Rx Android - дождитесь ответа сервера

Я использую RxJava и Retrofit в приложении для Android для получения данных с сервера. У меня есть тестовая активность с этим кодом.

    String text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewMenu = (LinearLayout) findViewById(R.id.view_menu);
        tabMenu.initTabBar(viewMenu, this);
        CapabilitiesHolder.createIfNotExist().getCapabilities().subscribe(this::handleResponse, RestErrorHandler::handle);
        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
    }



    private void handleResponse(CapabilitiesResponse capabilitiesResponse) {
        if (capabilitiesResponse.isSuccess()) {
            text = capabilitiesResponse.getSupportedCurrencies().get(0).getDescription();
        } else {
            RestErrorHandler.handle(null, capabilitiesResponse);
        }
    }

И класс Singleton для хранения данных с сервера в течение всего жизненного цикла приложения.

public class CapabilitiesHolder {


    private static CapabilitiesHolder mInstance = null;

    private CapabilitiesResponse capabilities;


    public static CapabilitiesHolder createIfNotExist() {
        if (mInstance == null) {
            mInstance = new CapabilitiesHolder();
        }
        return mInstance;
    }

    private CapabilitiesHolder() {
        requestCapabilities();
    }

    public Observable<CapabilitiesResponse> getCapabilities() {
        return Observable.fromCallable(() -> capabilities);
    }

    private CompositeSubscription compositeSubscription = new CompositeSubscription();

    private void requestCapabilities() {
        Observable<CapabilitiesResponse> o = RestServiceFactory.get().getServerCapabilities();
        compositeSubscription.add(o.subscribe(this::handleResponse, RestErrorHandler::handle));
    }

    private void handleResponse(CapabilitiesResponse capabilitiesResponse) {
        if (capabilitiesResponse.isSuccess()) {
            capabilities = capabilitiesResponse;
        } else {
            RestErrorHandler.handle(null, capabilitiesResponse);
        }
    }

    public void update() {
        mInstance = null;
        mInstance = new CapabilitiesHolder();
    }
}

Поэтому, когда моя тестовая активность создается впервые и сразу же вызывает CapabilitiesHolder.createIfNotExist().getCapabilities(), тост пуст, потому что данные в ответ требуют некоторого времени для загрузки. Когда чуть позже позвонил onCreate, все в порядке.

Вопрос в том, как я могу заставить (используя RxJava?) getCapabilities() метод ждать ответа от сервера перед вызовом.

Заранее спасибо!


person Dmitry Smolyaninov    schedule 10.02.2017    source источник


Ответы (2)


Краткий ответ - не блокируйте поток пользовательского интерфейса и ничего не ждите.

Переместите свой Toast в метод, который обрабатывает ответ

 private void handleResponse(CapabilitiesResponse capabilitiesResponse) {
    if (capabilitiesResponse.isSuccess()) {
        text = capabilitiesResponse.getSupportedCurrencies().get(0).getDescription();
        // Toast here 
    } else {
        RestErrorHandler.handle(null, capabilitiesResponse);
    }
person OneCricketeer    schedule 10.02.2017
comment
Спасибо за совет. Но, как я уже говорил, это тестовая активность, поэтому Toast вообще будет удален. Основной вопрос был о том, как я могу заставить CapabilitiesHolder.createIfNotExist().getCapabilities() this возвращать результат, когда он будет готов, вместо того, чтобы возвращать null после первого вызова. - person Dmitry Smolyaninov; 10.02.2017
comment
Он не возвращает ноль. Метод getCapabilities не блокирует (и не должен) блокировать. Запрос просто не завершился в момент вашего метода Toast. - person OneCricketeer; 10.02.2017
comment
У вас есть обработчик обратного вызова, который устанавливает ответ. Неважно, тостируете ли вы или обновляете свой пользовательский интерфейс. Вот что я говорю - person OneCricketeer; 10.02.2017

Я предлагаю вам перестроить свой класс CapabilitiesHolder class. Если вы хотите использовать этот держатель таким образом, вы не должны запрашивать какие-либо данные внутри конструктора. Кроме того, блокирование потока пользовательского интерфейса является плохой практикой.

private CapabilitiesHolder() {
    //empty
}

public Observable<CapabilitiesResponse> getCapabilities() {
    if(capabilities!=null){
        return Observable.fromCallable(() -> capabilities);
    } else {
        return RestServiceFactory.get()
                .getServerCapabilities()
                .doOnNext(capabilitiesResponse -> capabilities = capabilitiesResponse);
    }
}
person YMY    schedule 13.02.2017