Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/227.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cassandra/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 主线程上的Okhttp响应回调_Android_Multithreading_Okhttp - Fatal编程技术网

Android 主线程上的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) {

我已经创建了一个助手类来处理我应用程序中的所有http调用。它是一个简单的okhttp单例包装器,如下所示(我省略了一些不重要的部分):

然后,在我的主要活动中,我使用以下帮助器类:

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){

                }
            }
        }
    });
 }