Android 主线程上的 Okhttp 响应回调

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24246783/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:55:44  来源:igfitidea点击:

Okhttp response callbacks on the main thread

androidmultithreadingokhttp

提问by Michael

I have created a helper class to handle all of my http calls in my app. It is a simple singleton wrapper for okhttp that looks like this (I have omitted some unimportant parts):

我创建了一个帮助程序类来处理我的应用程序中的所有 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);
    }

}

Then, in my main activity, I use this helper class :

然后,在我的主要活动中,我使用这个助手类:

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
            }
        });

onSuccessthrows an exception when the code runs :

onSuccess代码运行时抛出异常:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

android.view.ViewRootImpl$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触摸其视图。

From my understanding, Okhttp callbacks run on the main thread so why do I get this error ?

根据我的理解,Okhttp 回调在主线程上运行,为什么会出现此错误?

** Just as a side note, I have created HttpCallbackinterface to wrap Okhttp's Callbackclass because I wanted to change the behaviour of onResponseand onFailureso I could unite the logic of handling failed responses due to i/o exception and failed responses due to server problems.

**正如一个方面说明,我已经创建HttpCallback界面包Okhttp的Callback类,因为我想改变的行为onResponseonFailure这样我就可以统一处理O异常,由于我没有反应/和由于服务器问题的失败响应的逻辑。

Thanks.

谢谢。

回答by Jake Wharton

From my understanding, Okhttp callbacks run on the main thread so why do I get this error ?

根据我的理解,Okhttp 回调在主线程上运行,为什么会出现此错误?

This is not true. Callbacks run on a background thread. If you want to immediately process something in the UI you will need to post to the main thread.

这不是真的。回调在后台线程上运行。如果您想立即处理 UI 中的某些内容,您将需要发布到主线程。

Since you already have a wrapper around the callback you can do this internally in your helper so that all HttpCallbackmethods are invoked on the main thread for convenience.

由于您已经在回调周围有了一个包装器,因此您可以在帮助程序内部执行此操作,以便HttpCallback为方便起见在主线程上调用所有方法。

回答by Michael

As Jake Wharton suggested, I had to run the callbacks on the main thread explicitly.

正如 Jake Wharton 所建议的,我必须在主线程上显式运行回调。

So I wrapped the calls to the callbacks with Runnablelike this:

所以我用这样的方式包装了对回调的调用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);
                    }
                });

            }
        });
 }

回答by Marcos Casagrande

I know it's an old question, but recently I encountered the same issue. If you need to update any view, you will need to use runOnUiThread()or post the result back on the main thread.

我知道这是一个老问题,但最近我遇到了同样的问题。如果您需要更新任何视图,则需要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);                
            }
        });
   }
});

回答by Manish Goyal

According to Retrofit documentation Callbackmethods are executed on UI thread by default until you provide a callback executor to RetrofitOR when using custom method return types using CallAdapterFactory

根据 Retrofit 文档,回调方法默认在 UI 线程上执行,直到您向Retrofit提供回调执行程序或使用CallAdapterFactory使用自定义方法返回类型