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
Okhttp response callbacks on the main thread
提问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
}
});
onSuccess
throws 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 HttpCallback
interface to wrap Okhttp's Callback
class because I wanted to change the behaviour of onResponse
and onFailure
so I could unite the logic of handling failed responses due to i/o exception and failed responses due to server problems.
**正如一个方面说明,我已经创建HttpCallback
界面包Okhttp的Callback
类,因为我想改变的行为onResponse
和onFailure
这样我就可以统一处理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 HttpCallback
methods 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 Runnable
like 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使用自定义方法返回类型时