【问题标题】:Unable to start receiver: android.os.NetworkOnMainThreadException with android JellyBean无法启动接收器:android.os.NetworkOnMainThreadException 与 android JellyBean
【发布时间】:2012-10-13 14:34:56
【问题描述】:

我正在尝试开发一个通过 json 资源每分钟更新一次的小部件,我的问题是当我尝试在 jellybean 上启动它时它会崩溃,而姜饼可以工作。

我看到here 我必须将所有互联网连接移到主线程,对吗? 目前我有一个名为 HttpRequest 的类:

public class HttpRequest {    
    private String url;

    public HttpRequest(String url)
    {       
        this.url = url;
    }

    public String GetContent() throws ClientProtocolException, IOException
    {
        HttpClient client = new DefaultHttpClient();
        HttpGet request = new HttpGet(url);
        HttpResponse response = client.execute(request);

        String html = "";
        InputStream in = response.getEntity().getContent();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder str = new StringBuilder();
        String line = null;
        while((line = reader.readLine()) != null)
        {
            str.append(line);
        }
        in.close();
        html = str.toString();
        return html;
    }
}

每一分钟都被调用 updateAppWidget() ,它是 WidgetProvider 类的一个方法。 在 updateAppWidget() 里面有:

HttpRequest r = new HttpRequest("http://www.hwlogos.com/test.json");
remoteViews.setTextViewText(R.id.ip, r.GetContent());

你能告诉我如何一步一步地解决它吗? 谢谢

【问题讨论】:

  • 不,你需要关闭主线程。
  • 我已经写过这个异常以及它在 Android 3.0 及更高版本中抛出的原因。查看此post 了解更多信息。

标签: android json multithreading httprequest android-4.2-jelly-bean


【解决方案1】:

正如建议的那样,AsyncTask 是要走的路。像这样更改您的代码:

private class HttpRequestTask extends AsyncTask<Context, Void, String> {

    private Context context;

    protected String doInBackground(Context... contextParam) {
        context = contextParam[0];
        HttpClient client = new DefaultHttpClient();
        HttpGet request = new HttpGet("http://www.hwlogos.com/test.json");
        HttpResponse response = client.execute(request);

        String html = "";
        InputStream in = response.getEntity().getContent();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder str = new StringBuilder();
        String line = null;
        while((line = reader.readLine()) != null)
        {
            str.append(line);
        }
        in.close();
        html = str.toString();
        return html;
     }

     protected void onPostExecute(String html) {
         AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
         RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
         remoteViews.setTextViewText(R.id.ip, html);
         appWidgetManager.updateAppWidget(new ComponentName(context, WidgetProvider .class), remoteViews);
     }
}

请注意 onPostExecute 中的代码,该代码执行更新应用小部件所需的额外工作。

然后像这样启动异步任务:

 new HttpRequestTask().execute(context);

【讨论】:

  • 最简单的解决方案是使 HttpRequestTask 类成为 WidgetProvider 类的内部类。另一种解决方案是将 remoteView 添加为 HttpRequestTask 的实例变量,并在调用 execute之前通过 setRemoteView 方法设置它>.
  • 我试过这样:pastebin.com/e2wDyBPW and Log.i("ERROR", "RECEIVED ID: " + remoteViews.toString());每次调用都会打印一个不同的id...我试图通过Downloader类的构造函数给remoteViews对象,并且存在同样的问题。
  • 每次调用 Downloader 时都会创建一个新的 remoteViews 实例。这真的是你想要的吗?你不应该创建一次 remoteViews 实例并多次调用 Downlader 吗?
  • 不,每个小部件应该是 1 个 remoteView...这段代码有什么问题?当我需要它时,我会得到它...
  • 我已经更改了代码并添加了从异步任务更新应用小部件所需的代码。
【解决方案2】:

您需要将您的网络连接从主线程中移出,然后移到后台线程上。如果您在主线程上使用网络,更高版本的 Android 将使应用程序崩溃。

最直接的解决方案是使用AsyncTask,它会在一个单独的线程上做一些工作(做你的网络获取),然后当它完成后让你在主线程上做后续工作。

this post 中有一个示例,其他许多可以在 SO 或 Google 上找到。

【讨论】:

    【解决方案3】:

    从下面的代码[来自线程]调用你的函数

    第 1 步:

    不是这两行

    HttpRequest r = new HttpRequest("http://www.hwlogos.com/test.json");
    remoteViews.setTextViewText(R.id.ip, r.GetContent());
    

    调用下面的代码行,

        Thread thread = new Thread()
        {
          @Override
          public void run() {
              try {
    
                // CALL YOUR FUNCTION FROM HERE
                HttpRequest r = new HttpRequest("http://www.hwlogos.com/test.json");            
                remoteViews.setTextViewText(R.id.ip, r.GetContent());
    
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
        };
    
    thread.start();
    

    第 2 步:

    如果上面的功能对你不起作用,那么

    使用此参考Link

    我希望这对你有用。谢谢。

    【讨论】:

    • 在你的类中声明这个“RemoteView remoteViews”对象为全局对象。
    • 我认为您在某个函数中创建了“RemoteView remoteViews = new”。
    • pastebin.com/BBK1Zq2N 我得到了这个 DEBUG: Id is: android.widget.RemoteViews@410917a8 DEBUG: real id is: android.widget.RemoteViews@40dd7470
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多