点击部分宝可梦详情页触发NullPointerException崩溃问题求助
让我帮你分析下这个问题——从错误日志和代码来看,你遇到的空指针异常根源其实很明确:
错误日志里的核心报错是:
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
这说明你在调用List.get(int)的时候,这个List本身是null。对应到你的代码里,就是pokemon.abilities[0].name这一行——你的pokemon.abilities字段为null,当你尝试获取第一个元素时就触发了崩溃,而且这是偶发的,说明只有部分宝可梦的这个字段没有被正确初始化。
问题出在哪?
看你的configDetalhes()方法,你发起了详情接口请求,但在observe回调里完全没有使用接口返回的详情数据,反而直接用了导航参数传递过来的pokemon对象。这个导航参数里的pokemon大概率是从列表页传过来的简略数据,可能只包含了部分字段(比如名字、ID),而abilities字段要么是null,要么部分宝可梦的这个字段是空列表,导致调用[0]时崩溃。
修复方案
我给你几个递进的修复步骤:
紧急修复:给abilities字段加空安全判断
在直接访问abilities[0]之前,必须先判断列表是否存在且不为空,用Kotlin的空安全语法可以轻松实现:private fun configDetalhes() { detalhesViewModel.getDetalhes(pokemon.id) detalhesViewModel.mResponse.observe(viewLifecycleOwner, { if (it.isSuccessful) { tv_detalhes_nome_pokemon.text = pokemon.nome // 空安全处理abilities字段 val abilityName = pokemon.abilities?.takeIf { it.isNotEmpty() }?.get(0)?.name ?: "无能力" tv_detalhes_habilidades_pokemon.text = abilityName tv_hp_detalhes_pokemon.text = pokemon.hp } }) }逻辑修正:使用详情接口返回的完整数据
既然你发起了详情接口请求,为什么不用返回的完整数据呢?导航参数里的pokemon只是简略数据,详情接口应该返回更完整的宝可梦信息,这也能从根源避免数据不全的问题:private fun configDetalhes() { detalhesViewModel.getDetalhes(pokemon.id) detalhesViewModel.mResponse.observe(viewLifecycleOwner, { response -> if (response.isSuccessful) { // 先判断body是否不为null val pokemonDetail = response.body() ?: return@observe tv_detalhes_nome_pokemon.text = pokemonDetail.nome // 同样做空安全处理 val abilityName = pokemonDetail.abilities?.takeIf { it.isNotEmpty() }?.get(0)?.name ?: "无能力" tv_detalhes_habilidades_pokemon.text = abilityName // 如果hp是Int类型,记得转成String tv_hp_detalhes_pokemon.text = pokemonDetail.hp.toString() } else { // 别忘了处理请求失败的情况,比如显示错误提示 Toast.makeText(context, "获取详情失败", Toast.LENGTH_SHORT).show() } }) }数据解析检查
还要确保你的PokemonItem数据类在解析接口返回的JSON时,abilities字段被正确映射。比如如果接口返回的abilities是null或者空数组,你的数据类应该把它解析成List<Ability>?或者emptyList(),而不是默认的null。举个例子:data class PokemonItem( val nome: String, val hp: Int, val abilities: List<Ability>? = emptyList() // 给个默认空列表,避免null ) data class Ability(val name: String)
额外建议
- 永远不要假设列表类型的字段一定不为null且不为空,尤其是从接口返回的数据,一定要做空安全判断。
- 可以在ViewModel里对返回的数据做预处理,比如把null的列表转换成空列表,这样UI层就不用重复做判断了。
内容的提问来源于stack exchange,提问作者user15567939

