Gson解析本地JSON遇MalformedJsonException问题排查与解决
Hey there! Let's break down why you're hitting that com.google.gson.JsonSyntaxException error and how to fix it.
What's Causing the Issue?
The root problem here is how Android's strings.xml handles text content—even when wrapped in CDATA. Here's what's going on:
- Android's resource compiler automatically processes strings in
strings.xml: it might strip or escape characters like quotes, newlines, or whitespace that are critical to valid JSON structure. - When you read the string with
getResources().getString()and write it to a local file, the resulting content isn't an exact copy of your original JSON. The missing quotes and newlines you spotted are direct evidence of this corruption. - CDATA helps with XML-reserved characters (like
<or>), but it doesn't prevent Android from normalizing whitespace or handling escape sequences in your JSON.
Step-by-Step Fixes
Let's go through the most reliable solutions, ordered from quick checks to robust fixes:
1. Verify Strings.xml Setup & File Writing (Quick Check)
First, make sure your CDATA is correctly formatted to preserve JSON structure:
<string name="default_keyboard_layout"><![CDATA[ { "keys": [ {"code": 65, "label": "A"}, {"code": 66, "label": "B"} ] } ]]></string>
When reading this string, avoid accidental manipulation (like trimming whitespace) that could break the JSON. Also, write to the local file with explicit UTF-8 encoding to prevent character loss:
val jsonString = resources.getString(R.string.default_keyboard_layout) val file = File(context.filesDir, "local_layout.json") OutputStreamWriter(FileOutputStream(file), StandardCharsets.UTF_8).use { it.write(jsonString) }
After writing, open the local file directly to confirm it matches your original JSON. If corruption still happens, move to the next solution.
2. Move JSON to the Assets Directory (Most Reliable)
Android's assets directory stores files as-is, with no automatic processing—this eliminates all resource system-related corruption. Here's how to implement it:
- Create an
assetsfolder insrc/mainif it doesn't exist. - Copy your full
index.jsonfile intoassets(name it something likekeyboard_layout.json). - Read the file directly from assets instead of strings.xml:
val jsonContent = context.assets.open("keyboard_layout.json").bufferedReader().use { it.readText() } // Parse directly or write to local file as needed val parser = JsonParser() val jsonElement = parser.parse(jsonContent)
This method guarantees you're working with the exact JSON content, no hidden modifications.
3. Debug the Content Flow
If you still want to use strings.xml, add debug logs to track the JSON at every step:
- Log the string right after reading from
strings.xml:Log.d("JSON", jsonString) - Log the content right after writing to the local file (read it back and log it)
Compare these logs to your original JSON to pinpoint exactly where corruption occurs—this will tell you if the issue is in reading the string or writing the file.
Final Notes
The assets directory approach is almost always the best choice for storing raw JSON in Android apps, especially for complex structures. It avoids all the pitfalls of Android's string resource processing and ensures your JSON stays intact.
内容的提问来源于stack exchange,提问作者Foobar

