解析JSONObjects并转换为Java对象时出现奇怪的问题

3
这是我第一次遇到一个非常奇怪的问题。我有一个下面提到的JSONObject: JSON主体的链接(由于字符限制,无法在此处粘贴JSON主体):http://kolam.vicz.in:7890/games_gifs/ 我正在解析上述一组JSONObjects并将它们转换为Java对象。以下是我解析这个JSON主体的代码。
private void getGameList() {
        StringRequest request = new StringRequest(Request.Method.GET, gameUrl, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                try {
                    JSONObject mainObject = new JSONObject(response);
                    JSONArray gamesArray = mainObject.getJSONArray("TracingGames");
                    Log.e(TAG, "gameArray length:" + gamesArray.length());
                    for (int i = 0; i < gamesArray.length(); i++) {
                        JSONObject obj = gamesArray.getJSONObject(i);
                        for (String str : getKeys(obj)) {
                            Log.e(TAG, str);
                            if (str.equalsIgnoreCase("kolam")) {

                                /*Section for Learn and Kolam Tracing games start*/
                                //TODO: Need to add the game names to the object (Need server side implementation as well)
                                KolamTracingGames kolamTracingGames = new KolamTracingGames();
                                kolamTracingGames.setKolamGifPath(obj.getString("path"));
                                kolamTracingGames.setKolamLevel(Integer.parseInt(str));
                                kolamTracingGames.setKolamGameName("Kolam Tracing");
                                kolamTracingGames.setX(getXCoordinates(obj));
                                kolamTracingGames.setY(getYCoordinates(obj));
                                kolamObjects.add(kolamTracingGames);
                                break;
                            } else if (str.equalsIgnoreCase("level")) {
                                LearnTracingGames learnTracingGames = new LearnTracingGames();
                                learnTracingGames.setLearnGameGifPath(obj.getString("path"));
                                learnTracingGames.setLearnGameLevel(Integer.parseInt(str));
                                learnTracingGames.setGameName("Learn Game");
                                learnTracingGames.setX(getXCoordinates(obj));
                                learnTracingGames.setY(getYCoordinates(obj));
                                learnGameObjects.add(learnTracingGames);
                                Log.e(TAG, learnGameObjects.size() + "");
                                break;
                            }
                        }
                    }

                    if (gameType.equalsIgnoreCase("Trace the Kolam")) {
                        kolamTraceAdapter = new KolamTraceAdapter(getActivity());
                        kolamTraceAdapter.getGameList(kolamObjects);
                        recyclerView.setAdapter(kolamTraceAdapter);
                    } else if (gameType.equalsIgnoreCase("Learn")) {
                        learnGameAdapter = new LearningGameAdapter(getActivity());
                        learnGameAdapter.getGameList(learnGameObjects);
                        Log.e(TAG, "learngameobject size:" + learnGameObjects.size());
                        recyclerView.setAdapter(learnGameAdapter);
                        Log.e(TAG, "Learn games");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(TAG, error.getMessage());
                if (getActivity() != null) {
                    Alerter.create(getActivity())
                            .setTitle(R.string.warning)
                            .setText(R.string.network_error)
                            .setDuration(2000)
                            .setBackgroundColorRes(R.color.dot_dark_screen1)
                            .show();
                }
            }
        });
        request.setTag(TAG);
        request.setRetryPolicy(new DefaultRetryPolicy(30000, 5, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        AppController.getInstance().addToRequestQueue(request);

我的问题是,有8个级别类型的对象和4个kolam对象(请参考JSON主体以获得清晰度)。我为它们分别拥有两个独立的POJO类。我能够正确解析JSON主体,但是当我尝试创建这些JSONObject的Java对象时,最内部的for循环没有完全运行。它在执行一次后就停止了。

如果我这样做(创建Java对象),则内部for循环不会完全执行(仅执行一次,但应该执行超过12次):

for (int i = 0; i < gamesArray.length(); i++) {
                        JSONObject obj = gamesArray.getJSONObject(i);
                        for (String str : getKeys(obj)) {
                            Log.e(TAG, str);
                            if (str.equalsIgnoreCase("kolam")) {

                                /*Section for Learn and Kolam Tracing games start*/
                                //TODO: Need to add the game names to the object (Need server side implementation as well)
                                KolamTracingGames kolamTracingGames = new KolamTracingGames();
                                kolamTracingGames.setKolamGifPath(obj.getString("path"));
                                kolamTracingGames.setKolamLevel(Integer.parseInt(str));
                                kolamTracingGames.setKolamGameName("Kolam Tracing");
                                kolamTracingGames.setX(getXCoordinates(obj));
                                kolamTracingGames.setY(getYCoordinates(obj));
                                kolamObjects.add(kolamTracingGames);
                                break;
                            } else if (str.equalsIgnoreCase("level")) {
                                LearnTracingGames learnTracingGames = new LearnTracingGames();
                                learnTracingGames.setLearnGameGifPath(obj.getString("path"));
                                learnTracingGames.setLearnGameLevel(Integer.parseInt(str));
                                learnTracingGames.setGameName("Learn Game");
                                learnTracingGames.setX(getXCoordinates(obj));
                                learnTracingGames.setY(getYCoordinates(obj));
                                learnGameObjects.add(learnTracingGames);
                                Log.e(TAG, learnGameObjects.size() + "");
                                break;
                            }
                        }
                    }

getKeys(JSONObject)方法如下:

private static String[] getKeys(JSONObject firstJSONObject) {
        Iterator keysToCopyIterator = firstJSONObject.keys();
        List<String> keysList = new ArrayList<>();
        while (keysToCopyIterator.hasNext()) {
            String key = (String) keysToCopyIterator.next();
            keysList.add(key);
        }
        return keysList.toArray(new String[keysList.size()]);
    }

但如果我避免在 for 循环 内创建对象,则内部的 for 循环 将完全运行。


只是出于好奇...你为什么要自己解析JSON?既然你在使用Android,你考虑过使用例如Gson吗? 因为这样理论上可以像写KolamTracingGmaes games = new Gson().fromJson(response, KolamTracingGames.class)一样简单。 - Daniel W.
我以为你有 break 语句。 - Yohannes Gebremariam
我已经尝试了各种可能的方法...如果我不创建那些Java对象,我可以轻松完整地解析JSON主体。只需注释掉那些对象的setter方法行即可使代码成功运行。但是如果我运行上述代码,则仅运行1次。 - sagar suri
这里的问题不在于break语句。@Yohannes - sagar suri
1个回答

2

但是如果我避免在for循环内创建对象,那么内部的for循环将完全运行。

Integer.parseInt("level")Integer.parseInt("kolam") 明显会导致崩溃。

解释

当你的任何一个 if (str.equalsIgnoreCase("kolam"))else if (str.equalsIgnoreCase("level")) { 匹配时,

你明显会出现崩溃,因为 str 将是 levelkolam,这些都不是 整数

解决方案:不要使用 str,而是获取值。

if (str.equalsIgnoreCase("kolam")) {
    //... code
    kolamTracingGames.setKolamLevel(obj.optInt(str));
    //... code                      ^^^^^^^^^^^^^^^
    break;
} else if (str.equalsIgnoreCase("level")) {
    //... code
    learnTracingGames.setLearnGameLevel(obj.optInt(str));
    //... code                          ^^^^^^^^^^^^^^^
    break;
}

很棒的解决方案。我刚从家里出来..一旦成功运行,我会更新..太神奇了。非常感谢。 - sagar suri
@Hiren,我很高兴能够帮到你,愿你编码愉快。 - Pavneet_Singh
我只是想知道,为什么Java编译器没有关于那个问题抛出任何错误或异常? - sagar suri
@Hiren,因为你使用了try-catch并且使用了Exception来处理每一个异常,但是仍然可以通过e.printStackTrace();在logcat中查看异常的详细信息。如果需要解析特定的异常,比如JSONException,只需添加相应的catch块即可使程序崩溃。 - Pavneet_Singh
在编程中,捕获预期异常进行快速调试是一种良好的实践。而不是使用 Exception,建议使用 catch (JSONException e) { 替换 catch (Exception e) { 来查看 NumberFormatException。 - Pavneet_Singh

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