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

Android Java入门:如何为ListView项动态添加行?

嘿,刚入坑Android Java就碰到ListView动态行的问题,太正常啦!我帮你一步步拆解这个需求,搞定它~

解决思路:嵌套布局的ListView实现

你的JSON是分组嵌套结构(Zone包含多个Van),所以核心是先解析数据,再给每个ListView项动态填充子行内容。


1. 先把JSON转成Java实体类

先根据你的JSON结构创建两个实体类,方便后续操作:

// 对应vannes数组里的单个阀门对象
public class Van {
    private String vn;
    private String ve;
    private String st;
    private String es;
    private String eo;

    // 自动生成Getter/Setter方法就行,Android Studio里按Alt+Insert快速生成
    public String getVn() { return vn; }
    public void setVn(String vn) { this.vn = vn; }
    public String getVe() { return ve; }
    public void setVe(String ve) { this.ve = ve; }
    public String getSt() { return st; }
    public void setSt(String st) { this.st = st; }
    public String getEs() { return es; }
    public void setEs(String es) { this.es = es; }
    public String getEo() { return eo; }
    public void setEo(String eo) { this.eo = eo; }
}

// 对应data数组里的单个区域对象
public class Zone {
    private String zi;
    private String zn;
    private List<Van> vannes;

    // 同样生成Getter/Setter
    public String getZi() { return zi; }
    public void setZi(String zi) { this.zi = zi; }
    public String getZn() { return zn; }
    public void setZn(String zn) { this.zn = zn; }
    public List<Van> getVannes() { return vannes; }
    public void setVannes(List<Van> vannes) { this.vannes = vannes; }
}

2. 解析JSON数据

我推荐用Google的Gson库来解析,比原生JSON工具简洁太多。先在app/build.gradle里加依赖:

dependencies {
    implementation 'com.google.code.gson:gson:2.10.1'
}

然后写解析逻辑:

// 假设你的JSON字符串存在jsonStr变量里(比如从网络请求拿到的)
Gson gson = new Gson();
JsonObject rootObj = gson.fromJson(jsonStr, JsonObject.class);
JsonArray zoneArray = rootObj.getAsJsonArray("data");

// 把JSON数组直接转成Zone列表
List<Zone> zoneList = gson.fromJson(zoneArray, new TypeToken<List<Zone>>(){}.getType());

3. 定义ListView的Item布局

先写每个区域的主布局list_item_zone.xml,里面包含区域名称和一个用来装阀门行的容器:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <!-- 区域名称 -->
    <TextView
        android:id="@+id/tv_zone_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textStyle="bold"/>

    <!-- 动态添加阀门行的容器 -->
    <LinearLayout
        android:id="@+id/ll_vannes_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginTop="8dp"/>

</LinearLayout>

再写单个阀门的行布局item_van.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="8dp"
    android:background="#f5f5f5"
    android:layout_marginBottom="4dp">

    <TextView
        android:id="@+id/tv_van_name"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:textSize="16sp"/>

    <TextView
        android:id="@+id/tv_van_status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:textColor="#666"/>

</LinearLayout>

4. 自定义ListView的Adapter

核心逻辑在这里:给每个区域项动态添加阀门行,还要注意复用View避免性能问题:

public class ZoneListAdapter extends BaseAdapter {
    private Context mContext;
    private List<Zone> mZoneList;

    public ZoneListAdapter(Context context, List<Zone> zoneList) {
        mContext = context;
        mZoneList = zoneList;
    }

    @Override
    public int getCount() {
        return mZoneList.size();
    }

    @Override
    public Object getItem(int position) {
        return mZoneList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        // 复用View,避免重复创建
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_zone, parent, false);
            holder = new ViewHolder();
            holder.tvZoneName = convertView.findViewById(R.id.tv_zone_name);
            holder.llVannesContainer = convertView.findViewById(R.id.ll_vannes_container);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
            // 复用前一定要清空容器,不然会重复添加旧的阀门行
            holder.llVannesContainer.removeAllViews();
        }

        // 填充当前区域的信息
        Zone currentZone = mZoneList.get(position);
        holder.tvZoneName.setText(currentZone.getZn());

        // 动态添加每个阀门的行
        for (Van van : currentZone.getVannes()) {
            View vanView = LayoutInflater.from(mContext).inflate(R.layout.item_van, holder.llVannesContainer, false);
            TextView tvVanName = vanView.findViewById(R.id.tv_van_name);
            TextView tvVanStatus = vanView.findViewById(R.id.tv_van_status);

            tvVanName.setText(van.getVn());
            // 这里可以根据你的需求拼接状态文本,比如把st、ve等字段组合起来
            tvVanStatus.setText("状态: " + van.getSt() + " | 启用: " + van.getVe());

            holder.llVannesContainer.addView(vanView);
        }

        return convertView;
    }

    // ViewHolder模式,提升性能
    static class ViewHolder {
        TextView tvZoneName;
        LinearLayout llVannesContainer;
    }
}

5. 在Activity里绑定ListView

最后一步,把Adapter设置给ListView:

public class MainActivity extends AppCompatActivity {
    private ListView mListView;
    private ZoneListAdapter mAdapter;
    private List<Zone> mZoneList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mListView = findViewById(R.id.list_view);

        // 这里替换成你的JSON解析逻辑,得到zoneList
        // mZoneList = ...

        mAdapter = new ZoneListAdapter(this, mZoneList);
        mListView.setAdapter(mAdapter);
    }
}

小提醒

如果你的阀门数据量很大,这种动态添加View的方式可能会有性能瓶颈,这时候更推荐用RecyclerView嵌套:外层RecyclerView展示区域,每个区域item里再放一个RecyclerView展示阀门,复用性会更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:31:14