【问题标题】:Android NetworkOnMainThreadException seems unsolvableAndroid NetworkOnMainThreadException 似乎无法解决
【发布时间】:2016-04-17 05:37:54
【问题描述】:

正在开发这个应用程序,它与网络服务器通信。

我正在使用 okHttp 发送 http 请求并获得响应。

由于某种原因,当请求花费很长时间时,我会收到 NetworkOnMainThreadException。

我找到的所有解决方案都行不通。

这是在接收数据需要很长时间之前有效的代码。

HttpGetRunnable.java

public class HttpGetRunnable implements Runnable {

  private Request request;
  private Response response;

  public HttpGetRunnable(String route) {
    String url = "http://10.0.2.2:8080" + route;
    request = new Request.Builder()
            .url(url)
            .build();
  }

  @Override
  public void run() {
    try{
        OkHttpClient client = new OkHttpClient();
        response = client.newCall(request).execute();
    } catch (IOException e) {
        e.printStackTrace();
        System.err.println(e.getMessage());
    }
  }

  public Response getResponse() {
    return response;
  }
}

用法

try {
    HttpGetRunnable httpGet = new HttpGetRunnable("/timesheet/" + user.getId());
    Thread thread = new Thread(httpGet);

    thread.start();
    thread.join();

    Response response = httpGet.getResponse();
    String jsonString = response.body().string();   
    // ^ throw exception on this line when taking to long
} catch (Exception e) {
    e.printStackTrace(System.out);
}

错误

04-16 23:06:53.042 31145-31145/com.example.jim.app I/System.out: android.os.NetworkOnMainThreadException
.. (no caused at)

到目前为止我尝试了什么:

  1. 使用 Callable(与 Runnable 相同,返回 Response)
  2. 使用 Callable 返回响应正文字符串
  3. 在 ExecutorService 单池中执行 runnable
  4. 在 ExecutorService 单一池中提交 callable,然后在 future.get 中提交
  5. 使用okHttp延迟@Override方法onFailed onResponse

我就是想不通。。 我在这里做错了什么?

谢谢

附言

使用这个版本com.squareup.okhttp3:okhttp:3.2.0

【问题讨论】:

标签: java android


【解决方案1】:

我在这里做错了什么?

您正在通过join() 阻塞主应用程序线程。摆脱它。

例如,here is a sample app 使用 OkHttp3 请求最新的 Stack Overflow 问题。我有一个专用的LoadThread 来处理 HTTP I/O:

/***
  Copyright (c) 2013-2016 CommonsWare, LLC
  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  use this file except in compliance with the License. You may obtain a copy
  of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
  by applicable law or agreed to in writing, software distributed under the
  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
  OF ANY KIND, either express or implied. See the License for the specific
  language governing permissions and limitations under the License.

  From _The Busy Coder's Guide to Android Development_
    https://commonsware.com/Android
 */

package com.commonsware.android.okhttp;

import android.util.Log;
import com.google.gson.Gson;
import java.io.BufferedReader;
import java.io.Reader;
import de.greenrobot.event.EventBus;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

class LoadThread extends Thread {
  static final String SO_URL=
      "https://api.stackexchange.com/2.1/questions?"
          + "order=desc&sort=creation&site=stackoverflow&tagged=android";

  @Override
  public void run() {
    try {
      OkHttpClient client=new OkHttpClient();
      Request request=new Request.Builder().url(SO_URL).build();
      Response response=client.newCall(request).execute();

      if (response.isSuccessful()) {
        Reader in=response.body().charStream();
        BufferedReader reader=new BufferedReader(in);
        SOQuestions questions=
            new Gson().fromJson(reader, SOQuestions.class);

        reader.close();

        EventBus.getDefault().post(new QuestionsLoadedEvent(questions));
      }
      else {
        Log.e(getClass().getSimpleName(), response.toString());
      }
    }
    catch (Exception e) {
      Log.e(getClass().getSimpleName(), "Exception parsing JSON", e);
    }
  }
}

但我只是在片段的onCreate() 中启动该线程。然后我不会尝试通过join() 阻止主应用程序线程。相反,我使用greenrobot的EventBus来找出数据加载的时间,然后使用它。

【讨论】:

  • 感谢您在这里帮助我。当我删除 join() 时,如果太长,它仍然会出现相同的错误, els 响应为空。我现在就去试试!!
  • @JimVercoelen:嗯,请记住,在工作完成之前您不能使用Response。 OkHttp 站点也有a sample of using Callback。我的猜测是您正试图从包含您的 thread.join() 调用的方法中返回 HTTP I/O 的结果。除非在后台线程上调用该方法本身,否则这将不起作用。
  • 是的,这就是我使用 join() 的原因,所以响应就在那里,但这似乎不是正确的方法。还尝试了该回调示例,但无法在 onResponse 方法中返回响应
  • @JimVercoelen:模式不是从后台线程return,而是从后台线程call。这就是我喜欢 greenrobot 的 EventBus 的原因之一:您可以从后台线程发布事件并将其传递到您的活动/片段/主应用程序线程上的任何内容。
  • 感谢您在这里帮助我!仍然新鲜与线程enco。在将数据检索到活动/片段后,我会尝试完成发布
猜你喜欢
  • 1970-01-01
  • 2018-08-24
  • 2022-01-07
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 2020-08-31
  • 2015-02-10
相关资源
最近更新 更多