我正在努力修复一个错误:
- 总是出现在我的Android 2.2, 2.3版本的模拟器中
- 从未在模拟器android版本4中发生。
- 从未在真实设备中发生过(android 4.*)
是以下IndexOutOfBoundsException异常:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{<myapppackage>}: java.lang.IndexOutOfBoundsException:
Invalid index 39, size is 0
在我的应用程序中,我从json文件中提取数据,我将其显示为文本。我已经隔离了bug的来源,它是当我调用这个方法:
public String getItemValue(int id, String s) {
List<JsonItems> list = new ArrayList<JsonItems>();
try {
// CONVERT RESPONSE STRING TO JSON ARRAY
JSONArray ja = new JSONArray(s);
// ITERATE THROUGH AND RETRIEVE
int n = ja.length();
for (int i = 0; i < n; i++) {
// GET INDIVIDUAL JSON OBJECT FROM JSON ARRAY
JSONObject jo = ja.getJSONObject(i);
// RETRIEVE EACH JSON OBJECT'S FIELDS
JsonItems ji = new JsonItems();
ji.id = jo.getInt("id");
ji.text= jo.getString("text");
list.add(ji);
}
} catch (Exception e) {
e.printStackTrace();
}
return list.get(id).text;
}
我的类JsonItems是非常基本的:
public class JsonItems{
int id;
String text;
}
示例从我的json文件:
[
{"id":0,"text":"some text 0"},
{"id":1,"text":"some text 1"},
{"id":2,"text":"some text 2"}
]
以下是我如何将json文件的内容处理成String
public static String fromJsonFileToString(String fileName, Context c) {
//JSONArray jArray = null;
String text = "";
try {
InputStream is = c.getAssets().open(fileName);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
text = new String(buffer);
} catch (IOException e) {
throw new RuntimeException(e);
}
return text;
}
我再次重复:IndexOutOfBoundsException永远不会发生在Android 4的设备上。*,只有当我在Android 2的模拟器上测试应用程序时才会发生这种情况。*
知道它是从哪里来的吗?
谢谢
第一个问题:
您没有正确读取输入流。调用available
实际上就是这样做的——它返回可用的要读取的数据量,当调用时。这个数字可以代表,也可以不代表文件的全部内容。
给你的阅读材料:
- 如何在Java中读取文件。
- 写入和创建文件
请注意,像Apache Commons IO这样的辅助库可以在一行代码(IOUtils.toString(inputStream)
)中读取文件内容。Android还不支持Java 7,但在该版本中有一个值得注意的替代方案,即Files.readAllLines
方法。在任何情况下,您都可以对文件读取代码进行如下所示的更改,它应该可以更好地工作:
public static String fromFileToString(String fileName, Context context) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
context.getAssets().open(fileName)));
String line = null;
StringBuilder builder = new StringBuilder(1024);
while ((line = reader.readLine()) != null) {
builder.append(line);
}
return builder.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
第二个问题:
你不做任何绑定检查,以确保你传递给'search'方法的参数:
public String getItemValue(int id, String s)
不超过最终计算的项列表的长度:
return list.get(id).text;
// ^
// -------------
// 'id' could be larger than the list size!
无论如何,您当前的设计根本不匹配您真正试图做的事情,即确定JSON数组中具有与您提供给方法相匹配的'id'字段的元素。为了能够做到这一点,您需要将JSON数据作为映射来处理。
public String getItemValue(int id, String json) {
if(json == null || json.trim().equals("")) return null;
Map<Integer, JsonItems> map = new HashMap<Integer, JsonItems>(4);
try {
JSONArray ja = new JSONArray(json);
int n = ja.length();
for (int i = 0; i < n; i++) {
JSONObject jo = ja.getJSONObject(i);
JsonItems ji = new JsonItems();
ji.id = jo.getInt("id");
ji.text = jo.getString("text");
map.put(Integer.valueOf(ji.id, ji);
}
} catch(NumberFormatException nfe) {
throw new IllegalArgumentException("Invalid JSON format");
} catch (Exception e) {
throw new RuntimeException(e);
}
JsonItems item = map.get(id);
return item != null ? item.text : null;
}
快速提示:
- JsonItems应该被称为JsonItem,以符合良好的Java命名标准
- 你应该真正解析和存储你的JSON只一次,以提高性能
- 您实际上只使用JSON数据的最小子集,您实际上可以在for循环中确定匹配节点并直接返回其值,而不必使用中间Java bean对象