Android 4.0以上版本支持JSON解析,但是低于4.0的版本不支持。

5

可能是重复问题:
JSON解析问题

我正在解析一个JSON文件(它是有效的)。它在Android 4.0-4.0.4上工作,但不适用于旧版本的Android。 这是我的清单的一部分:

<uses-sdk
    android:minSdkVersion="7"
    android:targetSdkVersion="14" />

这是我的解析代码:

public JSONObject getJSONFromUrl(String url) {
    try {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);

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

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                is, "UTF-8"), 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 {
        jObj = new JSONObject(json);
    } catch (JSONException e) {
        Log.e("JSON Parser", "Error parsing data " + e.toString());
    }

    return jObj;

}

在旧设备上,我收到以下错误消息(但如我所说,新的Android设备上没有):

org.json.JSONException:无法将类型为java.lang.String的值转换为JSONObject

我完全不知道为什么它可以在Android 4上工作,但不能在旧设备上工作。

这里找到Json。


粘贴整个JSON在这里!或尝试在www.jsonlint.com上验证。我怀疑JSON存在问题。 - Vipul
正如我所说(并且我现在再次通过jsonlint.com验证),它是有效的JSON...奇怪的是,它在Android 4上可以工作... - user754730
你确定两个设备上的org.json库版本是相同的吗?此外,增加你的缓冲读取器的缓冲区大小。 - wdziemia
是的,我在运行2.1版本的模拟器和设备以及运行4.0版本的手机上执行了完全相同的构建。好的,我会尝试一下。但如果它在一个设备上可以工作,为什么在另一个设备上不行呢? - user754730
看起来好像不行... 它只是说 Content-Type: text/plain。我怎么改变它?在服务器上吗? - user754730
显示剩余5条评论
12个回答

3
可能在较新版本的Android中,JSONObject解析器已变得更加宽容。你收到的错误信息似乎是由于JSON格式存在问题,尤其是在接收方。

建议你将下载得到的JSON写入文件,并与原始文件进行比较,以查看下载逻辑是否有问题。


更新

我无法重现你的问题。在Android 4.0.3、2.3.3、2.2和2.1上,使用以下活动(注意:我懒得把外部存储路径写死)从外部存储加载该JSON完全没有问题:

package com.commonsware.jsontest;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import org.json.JSONException;
import org.json.JSONObject;

public class JSONTestActivity extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    try {
      BufferedReader in=
          new BufferedReader(new FileReader("/mnt/sdcard/test.json"));
      String str;
      StringBuilder buf=new StringBuilder();

      while ((str=in.readLine()) != null) {
        buf.append(str);
        buf.append("\n");
      }

      in.close();
      JSONObject json=new JSONObject(buf.toString());

      ((TextView)findViewById(R.id.stuff)).setText(json.toString());
    }
    catch (IOException e) {
      Log.e(getClass().getSimpleName(), "Exception loading file", e);
    }
    catch (JSONException e) {
      Log.e(getClass().getSimpleName(), "Exception parsing file", e);
    }
  }
}

尝试过了,但是它生成的文件与我在服务器上的文件完全相同。 - user754730
@user754730:除非您能提供一个可以重现错误的项目,否则我怀疑任何人都无法真正帮助您。 - CommonsWare
@user754730:嗯,我们肯定需要引起错误的JSON。 - CommonsWare
@user754730:我会尽快在接下来的24小时内查看这个问题。 - CommonsWare

2
通常在Android中通过Http连接创建JSON对象的步骤如下:
  1. 打开连接并获取响应。
  2. 获取内容并创建一个字符串构建器。
  3. 将字符串构建器转换为JSON数组对象(您尚未执行此步骤)。
  4. 从JSON数组对象中获取JSON对象。
我认为您错过了将String Buffer(sb)转换为JSON数组对象的步骤。相反,您直接从String Buffer创建了JSON对象。我不知道它在Android 4.0中是如何工作的。 修改后的代码如下:
public JSONObject getJSONFromUrl(String url) {
    try {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);

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

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                is, "UTF-8"), 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 {
       JSONArray jObj = new JSONArray(json);
    } catch (JSONException e) {
        Log.e("JSON Parser", "Error parsing data " + e.toString());
    }

    return jObj;

}

您可以通过传递索引值来获取json对象,例如:

jObj.getJSONObject(i); /*i是一个整数,表示索引值*/


非常感谢您的这种方法!不幸的是,它既不能在2.1/2.2上工作,也不能在4.0上工作 :( - user754730

2

你好,我使用了以下代码,在2.2和2.3.3版本中没有出现任何错误,代码非常简单。

import java.io.IOException;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class NannuExpActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        try {
            JSONObject jo = getJSONObjectFromUrl("http://pastebin.com/raw.php?i=Jp6Z2wmX");
            for(int i=0;i<jo.getJSONArray("map_locations").length();i++)
            Log.d("Data",jo.getJSONArray("map_locations").getJSONObject(i).getString("title"));
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }

    public JSONObject getJSONObjectFromUrl(String url) throws ClientProtocolException, IOException, JSONException{
        JSONObject jobj = null;
        HttpClient hc = new DefaultHttpClient();
        HttpGet hGet = new HttpGet(url);
        ResponseHandler<String> rHand = new BasicResponseHandler();
        String resp = "";
        resp = hc.execute(hGet,rHand);
        jobj = new JSONObject(resp);    
        return jobj;
    }
}

希望这有所帮助。

2

我使用以下代码进行JSON处理,该代码能够兼容所有Android版本。

List<NameValuePair> postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("data", qry));
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(postParameters);

HttpPost request = new HttpPost(your url);
request.setEntity(formEntity);

HttpResponse rp = hc.execute(request);
Log.d("UkootLog", "Http status code " + rp.getStatusLine().getStatusCode());

if (rp.getStatusLine().getStatusCode() == HttpStatus.SC_OK
    || rp.getStatusLine().getStatusCode() >= 600) {
  Log.d("JsonLog", "Success !!");
  String result = EntityUtils.toString(rp.getEntity());
} else {
  Log.d("UkootLog", "Failed while request json !!");
}

我希望这能对您有所帮助。


2

这里的解决方案将会解决你的问题,这是由于服务器返回的utf-8编码引起的。

JSON解析问题


1
你尝试过JSONParser吗?
这是我使用的一个例子:
   JSONObject json = new JSONObject();
   JSONParser jsonParser = new JSONParser(); 


    try {

        if(jsonString != null)
            json =  (JSONObject) jsonParser.parse(jsonString);

    } catch (ParseException e) {        
        e.printStackTrace();
    }

1

我复制了你的代码,并使用{{link1:http://pastebin.com/raw.php?i=Jp6Z2wmX}}作为输入到你的getJSONFromUrl(String url)方法。有趣的是,我无法重现你的问题(使用多个AVD和/或目标API 15、10或7的组合)。

我注意到一些事情:

  • InputStream isString jsonJSONObject jObj在你的getJSONFromUrl()方法外部声明,有可能它们在运行于一个API上时受到你代码的其他部分的不同影响。

  • 看着你得到的异常,很可能是由于JSONObject构造函数的输入String为空字符串("")所引起的。是否可能你的服务器以某种方式向旧版Android提供了不同的数据?

这是我的建议:

  • 将以下代码添加到您的getJSONFromUrl()方法的顶部:

    InputStream is = null;
    String json = null;
    JSONObject jObj = null;
    
  • 在最后两个try-catch块之间添加一行调试代码,以打印下载的字符串,如下所示:

    // ----- cut ----
        Log.e("Buffer Error", "Error converting result " + e.toString());
    }
    
    Log.d("getJSONFromUrl", "json=(" + json + ")");
    
    try {
        jObj = new JSONObject(json);
    // ----- cut ----
    

我认为在您进行上述更改之一或两者之后,我们将更了解您的问题 :)


非常感谢你的帮助! 在此之前,我已经将这三行代码放入了我的程序中... 然后我尝试了日志记录的东西,它只是打印出了完整的JSON,然后像以前一样抛出了异常 :( - user754730
1
有趣,你能否尝试调用你的 getJSONFromUrl(url) 方法并将 http://pastebin.com/Jp6Z2wmXhttp://pastebin.com/raw.php?i=Jp6Z2wmX 作为 url 值传递?如果你能把这两个的 logcat 输出放在 pastebin 上,我会非常好奇的。 - Joe
哇,奇怪的是它在Pastebin上完美地在2.2和4.0上运行。但我真的不知道为什么? 所以目前情况是这样的: Android 4 + 我们的服务器 = 可以工作, Android < 4 + 我们的服务器 = 无法工作, Android 4 + Pastebin = 可以工作, Android < 4 + Pastebin = 可以工作。 - user754730
哇,我仍然无法真正相信...我们有一个租用的服务器,运行Apache。也许那就是问题所在?或者我应该从JSON文件中转义奇怪的字符(如ö,ä,ü)? - user754730
是的,在浏览器本身中它确实连接了... 它也正确显示了JSON... 我还尝试过转义德语umlaut,但那也没有帮助... 我会继续努力找到pastebin和我们服务器之间的区别... - user754730
显示剩余2条评论

1

在这行代码中,变量json的类型是什么?json = sb.toString();

它是一个字符串吗?如果它是一个JSONObject,将其类型更改为String,你的代码就会完美运行。


另一个需要注意的问题是异常处理:如果在构建字符串时第一个块中抛出异常,似乎JSONObject初始化将尝试使用一些错误的数据。

无论如何,试试这个(我怀疑你的下载方法有问题):

public JSONObject getJSONFromUrl(String url) {
    try {
        HttpPost postMethod = new HttpPost(SERVER_URL);
        ResponseHandler<String> res = new BasicResponseHandler();
        ResponseHandler<String> res = new ResponseHandler<String>() {
            public String handleResponse(final HttpResponse response) throws HttpResponseException, IOException {
                StatusLine statusLine = response.getStatusLine();
                if (statusLine.getStatusCode() >= 300) {
                    throw new HttpResponseException(
                    statusLine.getStatusCode(),
                    statusLine.getReasonPhrase());
                }
                HttpEntity entity = response.getEntity();
                return entity == null ? null : EntityUtils.toString(entity, "UTF-8");
            }
        };

        String response = (new DefaultHttpClient()).execute(postMethod, res);
        return new JSONObject(json);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

很遗憾,在Android 2.2上这也不起作用...但是在Android 4上可以... - user754730

1

我不太确定为什么您会遇到这个错误。但我之前也遇到过类似的问题,通过更改字符集解决了它。尝试使用 iso-8859-1 而不是 UTF-8


这实际上是我之前所拥有的。在任何一个版本上都不起作用 :( - user754730

1

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