2017-02-20 136 views
3

У меня есть запрос на цепочку RxJava, который должен освобождать некоторые блокировки onError() или onComplete(), поэтому, в основном, моя проблема: когда я устанавливал время ожидания, подключения и записи OkHttpClient, я не получаю желаемого поведения. Я использую Retrofit2 и OkHttp3.6.0 Вот мой клиент упрощена:HTTP FAILED: java.net.SocketException: Socket closed; не запускает методы обработки исключений

OkHttpClient.Builder builder = new OkHttpClient.Builder() 
      .readTimeout(30, TimeUnit.SECONDS) 
      .connectTimeout(30, TimeUnit.SECONDS) 
      .writeTimeout(30, TimeUnit.SECONDS) 
OkHttpClient okHttpClient = builder.build(); 

Вот упрощенный вариант запроса цепи у меня есть:

public <T extends Response> Observable<T> doSomething(Observable<T> base) { 
    isLocked = true; 
    return someApiCall() 
       .flatMap(apiResponse -> handleResponse(apiResponse, base) 
        .doOnError(throwable -> { 
         isLocked = false; 
        }) 
        .doOnCompleted(() -> { 
         isLocked = false; 
        })); 
} 

handleResponse() делает другой вызов API и возвращает Observable<Response<Something>> но, как я уже сказал, он иногда терпит неудачу с HTTP FAILED: java.net.SocketException: Socket closed, и он никогда не заканчивает Observable, поэтому onError() или onComplete() никогда не вызываются. Я тоже пробовал onTerminate(), но не повезло. Когда я удаляю настройки таймаута из OkHttlClient, на самом деле происходит выброс и обнаружение SocketException, который освобождает переменную isLocked. Я попробовал обернуть оператор return handleResponse() с блоком try {} catch (Exception e) {}, но даже это не поймает SocketException, когда установлены пользовательские таймауты. Есть идеи?

+0

делает ручкуResponse также переделать звонок? что вы определяете как «закончить наблюдаемый»? любой, как может быть проблема, поскольку кажется, что вы применяете doOnError/Completed только к внутреннему flatMapped, поэтому - someApiCall() может выйти из строя, и вы не поймаете его – yosriz

+0

да, он делает запрос на доработку. Как я уже упоминал, это упрощенная цепочка, реальная должна быть оригинальной. ApiCall (fail) -> apiCallOne -> apiCallTwo -> originalApiCall (это цепочка продления сеанса). Я попытался добавить как doOnError(), так и doOnTerminate во внешний вызов, но без везения. Проблема в том, что все остальные исключения попадают в цепочку, за исключением закрытого Socket –

+0

, я вижу, что происходит с SocketException? как вы знаете, что это изложение? – yosriz

ответ

0

Оказывается, что запрос получал отписался, что вызвало появление ошибки HTTP FAILED: java.net.SocketException: Socket closed, поэтому решение было просто добавить этот код в цепи:

.doOnUnsubscribe(() -> { 
    isLocked = false; 
}) 

Я до сих пор не понимаю, почему пользовательское значение тайм-аута запускало SocketException, но я полагаю, что сокет ожидал истечения времени ожидания и закрытия или завершения запроса и закрытия, но он был прерван вызовом unsubscribe и таким образом неожиданно закрыт.

0

В модификации 2 исключения ниже/выше уровня HTTP не сообщаются как Response<?>, а как фактические исключения через onError.

В вашем случае вы должны переместить doOnError/doOnCompleted из flatMap; поскольку они прямо сейчас отвечают на ошибки, сгенерированные только в handleResponse, но этот метод не будет вызываться, если someApiCall возвращает ошибку Observable.

+0

Я знаю это, и я попытался добавить doOnError и doOnCompleted к внешнему вызову тоже, но не повезло, даже doOnTerminate и doAfterTerminate, которые никогда не достигаются (в случае исключения Socket). Реальная проблема заключается в том, что все остальные исключения попадают в цепочку, за исключением закрытого Socket, который, похоже, обрабатывается где-то еще ... –

+0

Можете ли вы обернуть вызов в 'defer'? Как 'Observable.defer (() -> someApiCall())' –

+0

Так как я довольно новичок в RxJava, не могли бы вы рассказать мне, что это будет хорошего? Я попробую, но я не знаю, чего ожидать. –

0

Я решил эту ситуацию в Android с опцией retryOnConnectionFailure (true), установленной вместе с создателем.

Учитывая, что Retrofit 2 просто получает объект OkHttpClient.