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

Android读取XML多维数组异常:属性值重复且列表元素单一

解决XML多维数组读取的两个问题

我来帮你搞定这两个困扰你的问题,先拆解下原因,再一步步给出修正方案:

问题根源分析

1. 所有属性都被name值覆盖的原因

你在Activity里获取TypedArray中属性值的方式完全走偏了:

String deviceName = item.getString(item.getResources().getIdentifier("name", "string", packageName));

这段代码是去全局的string资源里找名为"name"的资源ID,而不是读取当前这个TypedArray里的item值。这就导致weight、repetition也都拿到了同一个全局的"name"资源值,自然所有属性都变成了name的值。

正确的做法是直接操作当前的TypedArray,通过item的name或者索引来获取对应的值。

2. 列表里全是同一个元素的原因

这个其实是第一个问题的连锁反应——因为所有属性值都错成了同一个,所以看起来所有元素都一模一样。不过还要提一句:虽然你每次循环都new了DeviceInformationOverview对象,但属性值错了,自然元素看起来重复。另外你的ResourceHelper循环逻辑也有小隐患,后面一起修正。


修正后的完整代码

1. 先给属性定义Styleable(可选但更健壮)

在res/values/attrs.xml中添加以下内容,让TypedArray可以通过name识别item:

<declare-styleable name="DeviceInformation">
    <attr name="name" format="string" />
    <attr name="weight" format="string" />
    <attr name="repetition" format="string" />
</declare-styleable>

2. 修正Activity中的取值逻辑

替换你原来的循环代码,改成正确的TypedArray取值方式:

for (TypedArray item : ResourceHelper.getMultiTypedArray(this, "device")) {
    // 通过Styleable获取对应item的索引
    int nameIndex = item.getIndex(R.styleable.DeviceInformation_name);
    int weightIndex = item.getIndex(R.styleable.DeviceInformation_weight);
    int repetitionIndex = item.getIndex(R.styleable.DeviceInformation_repetition);

    // 读取对应的值
    String deviceName = item.getString(nameIndex);
    String weight = item.getString(weightIndex);
    String repetition = item.getString(repetitionIndex);

    // 创建新的对象并赋值
    DeviceInformationOverview deviceInfo = new DeviceInformationOverview();
    deviceInfo.setDeviceName(deviceName);
    deviceInfo.setWeight(weight);
    deviceInfo.setRepetitionCount(repetition);
    devices.add(deviceInfo);

    // 必须回收TypedArray,避免内存泄漏
    item.recycle();
}

如果觉得Styleable麻烦,也可以直接按固定索引取值(因为你的XML中每个array的item顺序固定):

for (TypedArray item : ResourceHelper.getMultiTypedArray(this, "device")) {
    String deviceName = item.getString(0);
    String weight = item.getString(1);
    String repetition = item.getString(2);

    DeviceInformationOverview deviceInfo = new DeviceInformationOverview();
    deviceInfo.setDeviceName(deviceName);
    deviceInfo.setWeight(weight);
    deviceInfo.setRepetitionCount(repetition);
    devices.add(deviceInfo);

    item.recycle();
}

3. 修正ResourceHelper的循环逻辑

原有的do-while会在找不到资源时抛出异常,改成更安全的循环方式:

import android.content.Context;
import android.content.res.TypedArray;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import ch.lbuehler.updateapp.R;

public class ResourceHelper {
    public static List<TypedArray> getMultiTypedArray(Context context, String key) {
        List<TypedArray> arrayList = new ArrayList<>();
        Class<R.array> resArrayClass = R.array.class;
        int counter = 0;

        while (true) {
            try {
                Field field = resArrayClass.getField(key + "_" + counter);
                int resourceId = field.getInt(null);
                TypedArray typedArray = context.getResources().obtainTypedArray(resourceId);
                arrayList.add(typedArray);
                counter++;
            } catch (NoSuchFieldException e) {
                // 找不到对应字段,说明所有数组已遍历完成
                break;
            } catch (Exception e) {
                e.printStackTrace();
                break;
            }
        }
        return arrayList;
    }
}

4. 补充Adapter的完整逻辑(修复不完整部分)

确保Adapter能正确绑定每个元素的数据:

public class TrainingPlanListAdapter extends ArrayAdapter<DeviceInformationOverview> {
    private final Activity context;
    private final List<DeviceInformationOverview> deviceList;

    public TrainingPlanListAdapter(Activity context, List<DeviceInformationOverview> deviceList) {
        super(context, R.layout.exercise_overview_item, deviceList);
        this.context = context;
        this.deviceList = deviceList;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = context.getLayoutInflater();
        View exerciseItem = inflater.inflate(R.layout.exercise_overview_item, parent, false);

        // 获取控件引用
        TextView weightField = exerciseItem.findViewById(R.id.weightInfo);
        TextView repetitionField = exerciseItem.findViewById(R.id.repeatitionInfo);
        Button deviceButton = exerciseItem.findViewById(R.id.buttonDevice);

        // 获取当前位置的设备信息
        DeviceInformationOverview currentDevice = deviceList.get(position);
        deviceButton.setText(currentDevice.getDeviceName());
        weightField.setText(currentDevice.getWeight());
        repetitionField.setText(currentDevice.getRepetitionCount());

        // 按钮点击事件
        deviceButton.setOnClickListener(v -> {
            // 这里补充你的跳转逻辑
        });

        return exerciseItem;
    }
}

总结

  • 核心问题是错误地使用全局资源ID获取TypedArray中的item值,导致所有属性值重复;
  • 修正取值逻辑后,每个元素的属性会正确读取,自然就不会出现"同一个元素"的假象;
  • 一定要记得回收TypedArray,避免内存泄漏;
  • 优化后的ResourceHelper循环逻辑会更稳定,不会因为找不到资源而抛出异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:35:41