You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JSON解析偶发NullPointerException问题排查求助

解决JSON解析与网络请求崩溃问题

问题背景

我使用以下Kotlin代码解析JSON文件更新应用内容,Google Play Console显示该代码偶尔崩溃(崩溃率4%),但多台设备测试均无错误。同时我疑惑:是否存在val stationAPP = gson.fromJson(body, StationAPP::class.java)未抛出异常,但JSON加载错误导致部分字段为空的情况?

后续补充报错信息,崩溃触发NullPointerException,定位到代码第1390行的toast.show()。


核心代码

fun fetchJson() {
    if (isNetworkAvailable()) {
        val request = Request.Builder().url(stationAPPJsonURL).build()
        client.newCall(request).enqueue(object : Callback {
            override fun onResponse(call: Call, response: Response) {
                val body = response.body?.string()
                val gson = GsonBuilder().create()
                try {
                    val stationAPP = gson.fromJson(body, StationAPP::class.java)
                    // ACTIE
                    actie_zichtbaar = stationAPP.actie_zichtbaar
                    actie_img = stationAPP.actie_img
                    actie_url = stationAPP.actie_url
                    // 省略部分代码
                } catch (error: JsonParseException) {
                    runOnUiThread {
                        val toast = Toast.makeText(applicationContext, "Problem loading JSON. Functionality may be limited for a while.", Toast.LENGTH_SHORT)
                        val view = toast.view!!.findViewById<TextView>(android.R.id.message)
                        toast?.let { view.gravity = Gravity.CENTER }
                        toast.setGravity(Gravity.CENTER, 0, 0)
                        toast.show()
                    }
                }
            }

            override fun onFailure(call: Call, e: IOException) {
                runOnUiThread {
                    val toast = Toast.makeText(applicationContext, "Problem loading JSON. Functionality may be limited for a while.", Toast.LENGTH_SHORT)
                    val view = toast.view!!.findViewById<TextView>(android.R.id.message)
                    view?.let { view.gravity = Gravity.CENTER }
                    toast.setGravity(Gravity.CENTER, 0, 0)
                    toast.show() // --> line 1390!!
                }
            }
        })
    }
}

崩溃日志

Exception java.lang.NullPointerException:
  at com.familiekoning.grolloo.MainActivity$fetchJson$1.onFailure$lambda-10 (MainActivity.kt:1390)
  at com.familiekoning.grolloo.MainActivity$fetchJson$1.$r8$lambda$lczurdfMtnZdFDn9iwHvPqw9_Pg
  at com.familiekoning.grolloo.MainActivity$fetchJson$1$$ExternalSyntheticLambda8.run
  at android.os.Handler.handleCallback (Handler.java:938)
  at android.os.Handler.dispatchMessage (Handler.java:99)
  at android.os.Looper.loop (Looper.java:250)
  at android.app.ActivityThread.main (ActivityThread.java:7806)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:958)

问题分析与修复方案

1. 崩溃原因定位

崩溃源于onFailure方法中的空指针异常,具体触发点:

  • Toast.makeText在系统资源紧张、applicationContext失效等极端场景下可能返回null,但代码中直接使用toast.view!!(非空断言)和toast.setGravity,一旦toast为null就会触发NullPointerException。

2. Gson解析字段为空的情况

确实存在Gson解析不抛异常但字段为空的场景:

  • JSON缺失对应字段,且StationAPP类的字段为可空类型(未设置默认值);
  • JSON字段类型不匹配,但Gson启用了宽松模式(lenient=true),会自动将不匹配的值设为null或默认值;
  • response.body?.string()返回null,但Gson解析null时会生成StationAPP实例,所有字段为默认值或null。

3. 具体修复步骤

修复空指针崩溃

将Toast相关代码改为安全调用,避免非空断言,同时抽成统一方法减少重复:

private fun showErrorToast() {
    runOnUiThread {
        val toast = Toast.makeText(applicationContext, "Problem loading JSON. Functionality may be limited for a while.", Toast.LENGTH_SHORT)
        toast?.let {
            val view = it.view?.findViewById<TextView>(android.R.id.message)
            view?.gravity = Gravity.CENTER
            it.setGravity(Gravity.CENTER, 0, 0)
            it.show()
        }
    }
}

之后在catch块和onFailure方法中直接调用showErrorToast()即可。

优化Gson解析逻辑

  • 解析前先判断body是否为空,提前处理异常:
val body = response.body?.string() ?: run {
    showErrorToast()
    return@onResponse
}
  • 给StationAPP字段设置默认值或标记为可空,避免空字段引发后续问题:
data class StationAPP(
    val actie_zichtbaar: Boolean = false,
    val actie_img: String? = null,
    val actie_url: String? = null
    // 其他字段
)
  • 启用Gson严格模式,强制解析错误抛出异常,便于排查问题:
val gson = GsonBuilder()
    .setLenient(false)
    .create()

4. 额外优化建议

  • 在onFailure中添加日志记录,便于追踪网络失败的具体原因:
override fun onFailure(call: Call, e: IOException) {
    Log.e("MainActivity", "JSON fetch failed", e)
    showErrorToast()
}
  • 检查isNetworkAvailable()实现的可靠性,避免误判网络状态;
  • 当Activity可能销毁时,使用弱引用持有上下文,避免内存泄漏或无效上下文导致的问题。

内容的提问来源于stack exchange,提问作者Patrick Koning

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:30:59