0

私は必死に次のようなバグを修正しようとしています:

  • 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ファイルのデータに影響を与えています。私はバグがどこから来ているのかを特定しました、それは私がこのメソッドを呼び出すときです:

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ファイルのコンテンツを文字列に処理する方法は次のとおりです

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はAndroid4.*を搭載したデバイスでは発生しません。これは、Android2.*を搭載したエミュレーターでアプリをテストした場合にのみ発生します。

それがどこから来ているのか考えていますか?

ありがとう

4

1 に答える 1

2

最初の問題

入力ストリームを正しく読み取っていません。呼び出すと、文字通りそれが実行されます。呼び出しが行われたときに、読み取ることができるavailableデータの量が返されます。この番号は、ファイルのコンテンツ全体を表す場合とそうでない場合があります

あなたのための読み物:

1行のコード()でファイルの内容を読み取ることができるApacheCommonsIOのようなヘルパーライブラリがあることに注意してくださいIOUtils.toString(inputStream)。AndroidはまだJava7をサポートしていませんが、そのリリースでは、この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);
    }
}

2番目の問題:

'search'メソッドに渡す引数を確認するために、境界チェックは行いません。

public String getItemValue(int id, String s)

最終的に計算するアイテムのリストの長さを超えないようにします。

return list.get(id).text;
//              ^
// -------------
// 'id' could be larger than the list size!

いずれにせよ、現在のデザインは、メソッドに提供するものと一致する「id」フィールドを持つJSON配列内の要素を決定するために、実際に実行しようとしていることとはまったく一致しません。これを実行できるようにするには、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は、優れたJava命名標準に準拠するために、JsonItemと呼ばれる必要があります。
  • パフォーマンスを向上させるには、JSONを1回だけ解析して保存する必要があります
  • 実際には、JSONデータの最小限のサブセットのみを使用しています。実際には、forループ内で一致するノードを判別し、中間のJavaBeanオブジェクトを使用せずにその値を直接返すことができます。
于 2013-03-11T14:57:32.020 に答える