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
相关产品推荐
相关产品推荐

