android 4.2中出现的android.os.NetworkOnMainThreadException错误

26

我在使用这段代码加载Json。它与Android 2.2一起很好地工作,但当我使用Android 4.2时,它会抛出android.os.NetworkOnMainThreadException异常,请给我解决方案。

 public class JSONParser {

    static InputStream is = null;

static JSONObject jObj = null;
static String json = "";

// constructor
public JSONParser() {

}

public JSONObject getJSONFromUrl(String url) {

    // Making HTTP request
    try {
        // defaultHttpClient
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet httpPost = new HttpGet(url);

            HttpResponse getResponse = httpClient.execute(httpPost);
           final int statusCode = getResponse.getStatusLine().getStatusCode();

           if (statusCode != HttpStatus.SC_OK) { 
              Log.w(getClass().getSimpleName(), 
                  "Error " + statusCode + " for URL " + url); 
              return null;
           }

           HttpEntity getResponseEntity = getResponse.getEntity();

        //HttpResponse httpResponse = httpClient.execute(httpPost);
        //HttpEntity httpEntity = httpResponse.getEntity();
        is = getResponseEntity.getContent();            

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        Log.d("IO", e.getMessage().toString());
        e.printStackTrace();

    }

    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                is, "iso-8859-1"), 8);
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
        }
        is.close();
        json = sb.toString();
    } catch (Exception e) {
        Log.e("Buffer Error", "Error converting result " + e.toString());
    }

    // try parse the string to a JSON object
    try {
        jObj = new JSONObject(json);
    } catch (JSONException e) {
        Log.e("JSON Parser", "Error parsing data " + e.toString());
    }

    // return JSON String
    return jObj;

}

}

我也在使用谷歌API。


问题已在此回答:https://dev59.com/4W435IYBdhLWcg3w4Uas - Patrick D
http://stackoverflow.com/a/12615724/1168654 - Dhaval Parmar
5个回答

81
在setContentView(R.layout.activity_main)之后,将以下代码写入MainActivity文件中:
if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}

将以下导入语句添加到您的Java文件中:

import android.os.StrictMode;

41
关闭StrictMode的方式不正确。正确的方式是在AsyncTask中调用网络操作,而不是关闭它。 - Sankar V
正如 @SankarV 所说,应该使用 AsyncTask 来完成,而不是关闭 strictmode。 - Mr.Noob
这不是推荐的做法。AsyncTask是更好的方式。 - Hiten Naresh Vasnani
有很多解决方案被推荐,但除了这个之外,没有一个能解决这个问题。 - Maria Cecilia Ancheta Calianga

13

这是正确的方法:

public class JSONParser extends AsyncTask <String, Void, String>{

    static InputStream is = null;

static JSONObject jObj = null;
static String json = "";

// constructor
public JSONParser() {

}
@Override
protected String doInBackground(String... params) {


    // Making HTTP request
    try {
        // defaultHttpClient
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet httpPost = new HttpGet(url);

            HttpResponse getResponse = httpClient.execute(httpPost);
           final int statusCode = getResponse.getStatusLine().getStatusCode();

           if (statusCode != HttpStatus.SC_OK) { 
              Log.w(getClass().getSimpleName(), 
                  "Error " + statusCode + " for URL " + url); 
              return null;
           }

           HttpEntity getResponseEntity = getResponse.getEntity();

        //HttpResponse httpResponse = httpClient.execute(httpPost);
        //HttpEntity httpEntity = httpResponse.getEntity();
        is = getResponseEntity.getContent();            

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        Log.d("IO", e.getMessage().toString());
        e.printStackTrace();

    }

    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                is, "iso-8859-1"), 8);
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
        }
        is.close();
        json = sb.toString();
    } catch (Exception e) {
        Log.e("Buffer Error", "Error converting result " + e.toString());
    }

    // try parse the string to a JSON object
    try {
        jObj = new JSONObject(json);
    } catch (JSONException e) {
        Log.e("JSON Parser", "Error parsing data " + e.toString());
    }

    // return JSON String
    return jObj;


}
protected void onPostExecute(String page)
{   
    //onPostExecute
}   
}

从主函数调用它:

mJSONParser = new JSONParser();
mJSONParser.execute();

你有测试过吗?不起作用。那个URL是什么?返回的对象在循环外部是不可访问的。 - Nasz Njoka Sr.

6
请确保您的UI线程上不要执行任何网络访问操作,而是应该在异步任务中执行。
你的应用在Android 3.0及以上版本崩溃的原因是,自HoneyComb以来,Android对UI线程的滥用已经变得更加严格。例如,当运行HoneyComb或更高版本的Android设备检测到在UI线程上进行网络访问时,将会抛出NetworkOnMainThreadException异常。
请参考此文

我会说自从HoneyComb,而不是HoneyComb和Ice Cream Sandwich。事实上,JB有相同的政策。 - Blackbelt

1
使用StrictMode,类似于以下内容:

使用StrictMode如下:

   if (android.os.Build.VERSION.SDK_INT > 9) {
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

        StrictMode.setThreadPolicy(policy); 
        }

2
关闭StrictMode的方法不正确。正确的方法是在AsyncTask中调用网络操作,而不是关闭它。他们提供的检查只是为了关闭吗? - Sankar V
我们也可以使用asynkTask,但对于我来说它能正常工作。 - Deepanker Chaudhary
是的,它可以工作,但不是最好的方法。他们提供了检查来确保开发人员在单独的线程中调用网络操作,而不是简单地关闭它。 - Sankar V
哦!谢谢,AsyncTask很好。 - Deepanker Chaudhary

1

android.os.NetworkOnMainThreadException 当您尝试在主线程(即您的主活动执行)上访问网络时出现。为避免此情况,您必须创建一个单独的线程或AsyncTaskRunnable实现来执行JSON数据加载。自HoneyComb以来,您无法在主线程上进一步执行网络任务。 这里是使用AsyncTask执行网络任务的实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接