Android 主线程上的Okhttp响应回调
我已经创建了一个助手类来处理我应用程序中的所有http调用。它是一个简单的okhttp单例包装器,如下所示(我省略了一些不重要的部分): 然后,在我的主要活动中,我使用以下帮助器类:Android 主线程上的Okhttp响应回调,android,multithreading,okhttp,Android,Multithreading,Okhttp,我已经创建了一个助手类来处理我应用程序中的所有http调用。它是一个简单的okhttp单例包装器,如下所示(我省略了一些不重要的部分): 然后,在我的主要活动中,我使用以下帮助器类: HttpUtil.get(url, new HttpUtil.HttpCallback() { @Override public void onFailure(Response response, Throwable throwable) {
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
}
});
HttpUtil.get(url,新的HttpUtil.HttpCallback(){
@凌驾
失败时公共无效(响应,可丢弃){
//处理失败
}
@凌驾
成功时公共无效(响应){
//
据我所知,Okhttp回调在主线程上运行,那么为什么会出现这个错误呢
这不是真的。回调在后台线程上运行。如果要立即处理UI中的某些内容,则需要发布到主线程
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);
}
});
}
});
因为你已经有了一个围绕回调的包装器,你可以在助手内部完成这项工作,这样所有的HttpCallback
方法都可以在主线程上调用,以方便使用。正如Jake Wharton所建议的,我必须在主线程上显式运行回调
因此,我用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);
}
});
}
});
根据改装文档,默认情况下,方法在UI线程上执行,直到您使用自定义方法返回类型提供回调执行器为止。Michael的上述响应是在调用活动中进行回调的一个非常好的解决方案,我将它用作我将要概述的解决方案的指南低(Kotlin溶液)
HttpCallback接口
interface HttpCallback {
fun onResponse(response: Response)
fun onFailure(call: Call, e: IOException)
}
接口的实现。我将调用活动作为弱引用传递,以执行UI更新
class ImageUploadCallback(activity: WeakReference<Activity>) : HttpCallback {
val _activity = activity
override fun onResponse(response: Response) {
if(_activity.get() != null){
val activty = _activity.get()!!
activty.runOnUiThread(Runnable {
//Update the UI to your hearts content
});
}
}
override fun onFailure(call: Call, e: IOException) {
//Your implemtnation here
}
}
最后,HttpProxy类中接受回调的代码
fun UploadImage(filename: String, sourceImageFile: File, mediaType: MediaType, callback: HttpCallback) {
//building up our request...and then calling
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
callback.onFailure(call, e)
}
override fun onResponse(call: Call, response: Response) {
response.use {
try{
callback.onResponse(response)
}
catch(e: Exception){
}
}
}
});
}
Android网络活动无法在主线程上运行。我没有使用Okhttp的经验,但我非常确定您在另一个线程上。我认为Okhttp在另一个线程上处理网络io,并在主线程上回调。至少我看到的创建者之一@jake wharton说,这是进行改造的原因。我发现了一个Calback
类。您可以尝试实现该类。@TmKVU我实际上是在client.newCall(request.enqueue()中的匿名类中实现的
。我从未从主线程派生过另一个线程,因此我怀疑Okhttp本身就是这样做的。我认为控制没有被转移回主线程。谢谢,事实上我必须在主线程上运行回调。你能看看我添加到下面答案中的代码吗?不确定这是否正确可以这样做,你会怎么做?Okhttp代码库是否包含特定于Android的示例?现在的问题是,在MainActivity中调用response.body().string()
会抛出Android.os.NetworkOnMainThreadException
(因为它是在主线程上执行的).此调用是否执行任何网络操作?我不认为回调应该在后台线程中而不是在UI上有什么大的原因,因为在大多数情况下,我们执行的网络调用希望它们在后台运行,但将结果发布在前端/UIOkHttp对主线程一无所知。它不是Android库,而是Java l此外,通过回拨初始数据,它允许流式响应,并可能在整个响应被消耗之前增量更新UI。“它不是Android库,而是Java库”-现在更有意义了。谢谢!你的上下文
来自哪里。当一个活动调用HttpUtil
必须是它的上下文
?我认为它不是很好。你可以尝试新处理程序(Looper.getMainLooper())
而不是新处理程序(context.getMainLooper())
您是否对该助手在更改片段或活动的配置时没有问题,因为cb在更改配置之前会引用旧对象?非常感谢,您救了我一天!这就是我一直在寻找的,谢谢,伙计,您让我的生活轻松了很多!完美…正是我想要的。这个问题是关于OkHttp,n的ot改造。改造会自动处理切换回主线程,OkHttp不会。
fun UploadImage(filename: String, sourceImageFile: File, mediaType: MediaType, callback: HttpCallback) {
//building up our request...and then calling
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
callback.onFailure(call, e)
}
override fun onResponse(call: Call, response: Response) {
response.use {
try{
callback.onResponse(response)
}
catch(e: Exception){
}
}
}
});
}