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

安卓应用接入Gson后偶发Random.nextInt抛IllegalArgumentException如何修复

认知正误确认

你认为「Gson解析出错应该抛出相关异常而非返回空列表」的认知不完全正确,以下两种场景Gson会返回空列表且不抛出任何异常:

  • 待解析的JSON内容为合法空数组[]
  • 配置了自定义容错类型适配器,对解析失败的数组类型静默返回空集合

如果解析过程中Gson确实抛出了JsonSyntaxException/JsonIOException等异常,但上层调用代码吞掉了所有Throwable,也会导致方法返回默认空值/空列表。


偶发空列表的可能原因

你本地无法复现的偶发空列表,大概率是以下几种场景导致的:

  • 上层调用getQuestionsFromJson的代码加了全局异常捕获,吞掉了资源读取、Gson解析过程中抛出的异常,静默给questionsFromJson赋了空默认值
  • 极少数定制ROM、应用分身/平行空间沙箱环境下,raw资源读取异常返回空流,空流被Gson解析为空列表
  • 多线程并发操作questionsFromJson,列表被其他线程执行了clear/批量remove操作,刚好在你调用size()时长度为0
  • 混淆规则偶发失效:Question类未加全@SerializedName注解,部分极端系统环境下字段被混淆导致解析结果为空

排查修复方案

第一步:完善解析逻辑,加异常埋点和兜底

修改getQuestionsFromJson方法,补全异常捕获、埋点上报和默认值逻辑:

private ArrayList<Question> getQuestionsFromJson(int id, Context context) {
    ArrayList<Question> result = new ArrayList<>(); // 初始化默认空列表,避免返回null
    Reader reader = null;
    try {
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        // 直接指定TypeToken为ArrayList<Question>,避免类型转换异常
        Type dtoListType = new TypeToken<ArrayList<Question>>(){}.getType();
        reader = new InputStreamReader(context.getResources().openRawResource(id));
        List<Question> tempList = gson.fromJson(reader, dtoListType);
        if (tempList != null) {
            result.addAll(tempList);
        }
        // 埋点:如果解析结果为空,上报设备ROM版本、资源ID有效性、应用运行环境等信息
        if (result.isEmpty()) {
            // 可接入自有埋点/第三方统计平台上报异常场景
        }
    } catch (Throwable t) {
        // 捕获所有异常,上报堆栈信息用于排查
        t.printStackTrace();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                // 可忽略IO关闭异常
            }
        }
    }
    return result;
}

第二步:调用处加防御性判断,避免崩溃

在使用列表前加长度校验,极端场景下走兜底逻辑:

questionsFromJson = getQuestionsFromJson(R.raw.ru, context);
// 列表为空时重试一次,或者直接加载预制的默认Question列表兜底
if (questionsFromJson.isEmpty()) {
    questionsFromJson = getQuestionsFromJson(R.raw.ru, context);
    if (questionsFromJson.isEmpty()) {
        // 走本地硬编码的兜底数据逻辑,保证列表至少有QUESTIONS_SIZE个元素
        questionsFromJson = getDefaultFallbackQuestions();
    }
}

for (int i = 0; i < QUESTIONS_SIZE; i++){
    // 极端情况再做一层判断,避免崩溃
    if (questionsFromJson.isEmpty()) {
        break;
    }
    int index = random.nextInt(questionsFromJson.size());
    int imageId = context.getResources().getIdentifier(questionsFromJson.get(index).getImage().replace(".png", "") , "drawable", packageName);
    questionsFromJson.get(index).setImageId(imageId);
    questions.add(questionsFromJson.remove(index));
}

第三步:排查潜在风险

  • 确认questionsFromJson是否为多线程共享变量,如果是需要给操作加同步锁,或者使用CopyOnWriteArrayList等线程安全实现
  • 给Question类加@Keep注解,所有字段加@SerializedName注解,避免混淆规则偶发失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 01:54:03