Okhttp ответные обратные вызовы на основной поток



Я создал вспомогательный класс для обработки всех моих http-вызовов в моем приложении. Это простая одноэлементная оболочка для okhttp, которая выглядит так (я опустил некоторые неважные части):



public class HttpUtil {

private OkHttpClient client;
private Request.Builder builder;

...

public void get(String url, HttpCallback cb) {
call("GET", url, cb);
}

public void post(String url, HttpCallback cb) {
call("POST", url, cb);
}

private void call(String method, String url, final HttpCallback cb) {
Request request = builder.url(url).method(method, method.equals("GET") ? null : new RequestBody() {
// don't care much about request body
@Override
public MediaType contentType() {
return null;
}

@Override
public void writeTo(BufferedSink sink) throws IOException {

}
}).build();

client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, Throwable throwable) {
cb.onFailure(null, throwable);
}

@Override
public void onResponse(Response response) throws IOException {
if (!response.isSuccessful()) {
cb.onFailure(response, null);
return;
}
cb.onSuccess(response);
}
});
}


public interface HttpCallback {

/**
* called when the server response was not 2xx or when an exception was thrown in the process
* @param response - in case of server error (4xx, 5xx) this contains the server response
* in case of IO exception this is null
* @param throwable - contains the exception. in case of server error (4xx, 5xx) this is null
*/
public void onFailure(Response response, Throwable throwable);

/**
* contains the server response
* @param response
*/
public void onSuccess(Response response);
}

}


потом, в моей основной деятельности, я использую этот вспомогательный класс :



HttpUtil.get(url, new HttpUtil.HttpCallback() {
@Override
public void onFailure(Response response, Throwable throwable) {
// handle failure
}

@Override
public void onSuccess(Response response) {
// <-------- Do some view manipulation here
}
});


onSuccess выдает исключение при запуске кода :




android.вид.ViewRootImpl$CalledFromWrongThreadException: только
исходный поток, который создал вид иерархии может прикоснитесь к его виду.




насколько я понимаю, обратные вызовы Okhttp выполняются в основном потоке, так почему я получаю эту ошибку ?



** так же, как Примечание стороны, я создал HttpCallback интерфейс, чтобы обернуть Okhttp это Callback класс, потому что я хотел изменить поведение onResponse и onFailure таким образом, я мог бы объединить логику обработки неудачных ответов из-за исключения ввода-вывода и неудачных ответов из-за проблем с сервером.



спасибо.

668   4  

4 ответов:

насколько я понимаю, обратные вызовы Okhttp выполняются в основном потоке, так почему я получаю эту ошибку ?

это не правда. Обратные вызовы выполняются в фоновом потоке. Если вы хотите немедленно обработать что-то в пользовательском интерфейсе, вам нужно будет отправить сообщение в основной поток.

поскольку у вас уже есть обертка вокруг обратного вызова вы можете сделать это внутри вашего помощника так, чтобы все HttpCallback методы вызываются в основном потоке для удобства.

Как предложил Джейк Уортон, мне пришлось явно запускать обратные вызовы в основном потоке.

поэтому я обернул вызовы обратных вызовов с Runnable такой:

private void call(String method, String url, final HttpCallback cb) {
    ...

    client.newCall(request).enqueue(new Callback() {
            Handler mainHandler = new Handler(context.getMainLooper());

            @Override
            public void onFailure(Request request,final Throwable throwable) {
                mainHandler.post(new Runnable() {

                    @Override
                    public void run() {
                        cb.onFailure(null, throwable);
                    }
                });

            }

            @Override
            public void onResponse(final Response response) throws IOException {
                mainHandler.post(new Runnable() {

                    @Override
                    public void run() {
                        if (!response.isSuccessful()) {
                            cb.onFailure(response, null);
                            return;
                        }
                        cb.onSuccess(response);
                    }
                });

            }
        });
 }

Я знаю, это старый вопрос, но недавно я столкнулся с такой же проблемой. Если вам нужно обновить любой вид, вам нужно будет использовать runOnUiThread() или отправить результат обратно в основной поток.

HttpUtil.get(url, new Callback() { //okhttp3.Callback
   @Override
   public void onFailure(Call call, IOException e) { /* Handle error **/ }

   @Override
   public void onResponse(Call call, Response response) throws IOException {

      String myResponse =  response.body().string();
      //Do something with response
      //...

      MyActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
               //Handle UI here                        
               findViewById(R.id.loading).setVisibility(View.GONE);                
            }
        });
   }
});

согласно документации по модернизации обратный звонок методы выполняются в потоке пользовательского интерфейса по умолчанию, пока вы не предоставите исполнителю обратного вызова модернизация или при использовании пользовательских типов возвращаемых методов с помощью CallAdapterFactory

Comments

    Ничего не найдено.