You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android ListView加载含空格JSON项点击崩溃问题及优化方案咨询

解决ListView点击含空格项崩溃的最优方案

这个问题的核心原因很明确:你现在是把列表项toString()的输出当成JSON来解析,但默认的toString()生成的根本不是标准JSON格式——比如你看到的{nome=SPACE CRASH, cf=12345674},里面的键和值都没有双引号,当值包含空格时,JSON解析器会把SPACE误认为是一个新的键,直接触发语法错误,也就是你遇到的org.json.JSONException: Unterminated object

字符串替换只是临时凑合用的办法,长期来看很容易踩坑(比如如果值里包含=或者,,替换逻辑会直接失效)。下面给你几个更可靠的最优解决方案:


方案1:保存原始结构化数据(推荐首选)

不要依赖toString()来传递数据,而是在Adapter的数据源中直接保存原始的JSONObject或者自定义的Model对象,点击列表项时直接获取这个对象,完全跳过字符串解析的步骤。

示例1:用自定义Model类(更符合Android开发规范)

首先定义对应JSON数据的Model类:

public class User {
    private String nome;
    private String cf;

    // 构造方法
    public User(String nome, String cf) {
        this.nome = nome;
        this.cf = cf;
    }

    // Getter方法
    public String getNome() { return nome; }
    public String getCf() { return cf; }

    // 如果需要转成标准JSON,用Gson/Jackson等序列化库
    public String toStandardJson() {
        return new Gson().toJson(this);
    }
}

然后初始化Adapter的数据源:

// 假设你从原始JSON数组解析出数据
List<User> userList = new ArrayList<>();
JSONArray jsonArray = new JSONArray(yourRawJsonString);
for (int i = 0; i < jsonArray.length(); i++) {
    JSONObject obj = jsonArray.getJSONObject(i);
    userList.add(new User(obj.optString("nome"), obj.optString("cf")));
}

// 设置ListView的Adapter(比如ArrayAdapter)
ArrayAdapter<User> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, userList);
listView.setAdapter(adapter);

最后处理点击事件:

listView.setOnItemClickListener((parent, view, position, id) -> {
    // 直接获取原始的User对象,不需要解析字符串
    User clickedUser = userList.get(position);
    
    // 直接使用属性,比如:
    String nome = clickedUser.getNome();
    String cf = clickedUser.getCf();
    
    // 如果确实需要JSON对象,用Model的toStandardJson方法生成标准JSON再解析
    try {
        JSONObject jsonObj = new JSONObject(clickedUser.toStandardJson());
        // 后续逻辑
    } catch (JSONException e) {
        e.printStackTrace();
    }
});

示例2:直接保存JSONObject

如果不想定义Model类,也可以直接把解析后的JSONObject存在列表里:

List<JSONObject> jsonList = new ArrayList<>();
JSONArray jsonArray = new JSONArray(yourRawJsonString);
for (int i = 0; i < jsonArray.length(); i++) {
    jsonList.add(jsonArray.getJSONObject(i));
}

// 设置Adapter时,重写getView来显示数据
listView.setAdapter(new BaseAdapter() {
    @Override
    public int getCount() { return jsonList.size(); }
    @Override
    public Object getItem(int position) { return jsonList.get(position); }
    @Override
    public long getItemId(int position) { return position; }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
        }
        TextView textView = convertView.findViewById(android.R.id.text1);
        JSONObject obj = jsonList.get(position);
        textView.setText(obj.optString("nome") + " | " + obj.optString("cf"));
        return convertView;
    }
});

// 点击事件直接拿JSONObject
listView.setOnItemClickListener((parent, view, position, id) -> {
    JSONObject clickedObj = jsonList.get(position);
    // 直接使用obj里的字段,比如clickedObj.optString("nome")
});

方案2:生成标准JSON格式的toString()(次选)

如果因为某些原因必须用toString()来传递数据,那一定要重写对象的toString()方法,让它输出标准JSON字符串,而不是默认的键值对格式。

比如在自定义Model类里重写toString:

@Override
public String toString() {
    // 用Gson生成标准JSON,确保键和值都带双引号
    return new Gson().toJson(this);
}

这样点击时拿到的toString结果就是{"nome":"SPACE CRASH", "cf":"12345674"},转JSONObject就不会出错了。


为什么不推荐字符串替换?

你的临时替换方案虽然能解决空格的问题,但如果JSON值里出现=,或者其他特殊字符,替换逻辑会直接失效,而且维护起来非常麻烦。比如如果nome的值是Hello=World, Test,替换后的字符串还是不符合JSON规范,依然会崩溃。

所以最稳妥的方式还是直接保存原始的结构化数据,避免从非标准字符串中解析JSON。

内容的提问来源于stack exchange,提问作者Marcus J.Kennedy

火山引擎 最新活动