如何在Android Studio中为RecyclerView设置异构JSON数据
如何在Android Studio中实现异构RecyclerView展示你的油价JSON数据
嘿,我来帮你搞定这个异构RecyclerView的需求!首先咱们得明确目标:你的JSON数据是同一日期下不同城市、不同公司的柴油/汽油价格,咱们可以把列表做成两种异构Item:一种是「城市标题项」(用来区分不同城市),另一种是「油价详情项」(展示具体的公司、油品类型和价格)。接下来一步步实现:
1. 创建数据模型类
咱们用密封类(Kotlin)或者父类+子类(Java)来统一两种Item类型,这样Adapter能轻松区分它们:
Kotlin 版本
// 基类,统一RecyclerView的所有Item类型 sealed class PriceListItem { // 城市标题Item data class CityTitle(val cityName: String) : PriceListItem() // 油价详情Item data class PriceDetail( val date: String, val price: Double, val company: String, val type: String ) : PriceListItem() } // 解析原始JSON用的实体类 data class RawPrice( val date: String, val price: Double, val company: String, val city: String, val type: String )
Java 版本(可选)
如果你用Java,可以写一个父类,然后两个子类,再加上getItemType()方法来区分:
// 基类 public abstract class PriceListItem { public static final int TYPE_CITY_TITLE = 0; public static final int TYPE_PRICE_DETAIL = 1; public abstract int getItemType(); } // 城市标题Item public class CityTitleItem extends PriceListItem { private String cityName; public CityTitleItem(String cityName) { this.cityName = cityName; } public String getCityName() { return cityName; } @Override public int getItemType() { return TYPE_CITY_TITLE; } } // 油价详情Item public class PriceDetailItem extends PriceListItem { private String date; private double price; private String company; private String type; // 构造器、getter省略 @Override public int getItemType() { return TYPE_PRICE_DETAIL; } } // 原始JSON解析用的实体类 public class RawPrice { private String date; private double price; private String company; private String city; private String type; // 构造器、getter、setter省略 }
2. 解析JSON并生成异构列表
先把原始JSON解析成RawPrice列表,然后按城市分组,再依次添加「城市标题Item」和该城市下的所有「油价详情Item」:
Kotlin 示例(用Gson解析)
// 假设你已经拿到了JSON字符串jsonString val gson = Gson() val rawPrices = gson.fromJson(jsonString, Array<RawPrice>::class.java).toList() // 按城市分组 val groupedByCity = rawPrices.groupBy { it.city } // 构建异构列表 val heterogeneousList = mutableListOf<PriceListItem>() groupedByCity.forEach { (city, prices) -> // 先添加城市标题 heterogeneousList.add(PriceListItem.CityTitle(city)) // 再添加该城市下的所有油价详情 prices.forEach { price -> heterogeneousList.add( PriceListItem.PriceDetail( date = price.date, price = price.price, company = price.company, type = price.type ) ) } }
3. 实现多类型RecyclerView Adapter
Adapter需要区分两种Item类型,创建对应的ViewHolder并绑定数据:
Kotlin 版本
class PriceAdapter(private val items: List<PriceListItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { companion object { private const val TYPE_CITY_TITLE = 0 private const val TYPE_PRICE_DETAIL = 1 } // 区分当前Item的类型 override fun getItemViewType(position: Int): Int { return when (items[position]) { is PriceListItem.CityTitle -> TYPE_CITY_TITLE is PriceListItem.PriceDetail -> TYPE_PRICE_DETAIL } } // 创建对应的ViewHolder override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { val inflater = LayoutInflater.from(parent.context) return when (viewType) { TYPE_CITY_TITLE -> { val view = inflater.inflate(R.layout.item_city_title, parent, false) CityTitleViewHolder(view) } TYPE_PRICE_DETAIL -> { val view = inflater.inflate(R.layout.item_price_detail, parent, false) PriceDetailViewHolder(view) } else -> throw IllegalArgumentException("未知的Item类型") } } // 绑定数据到ViewHolder override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (val item = items[position]) { is PriceListItem.CityTitle -> (holder as CityTitleViewHolder).bind(item) is PriceListItem.PriceDetail -> (holder as PriceDetailViewHolder).bind(item) } } override fun getItemCount() = items.size // 城市标题ViewHolder inner class CityTitleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val tvCity: TextView = itemView.findViewById(R.id.tv_city_title) fun bind(item: PriceListItem.CityTitle) { tvCity.text = item.cityName } } // 油价详情ViewHolder inner class PriceDetailViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val tvCompany: TextView = itemView.findViewById(R.id.tv_company) private val tvType: TextView = itemView.findViewById(R.id.tv_fuel_type) private val tvPrice: TextView = itemView.findViewById(R.id.tv_price) private val tvDate: TextView = itemView.findViewById(R.id.tv_date) fun bind(item: PriceListItem.PriceDetail) { tvCompany.text = item.company tvType.text = item.type tvPrice.text = String.format("%.2f ₹", item.price) // 按需求格式化价格 tvDate.text = item.date } } }
4. 创建Item布局文件
需要两个布局文件分别对应两种Item:
item_city_title.xml(城市标题布局)
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tv_city_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:background="#f5f5f5" android:textSize="18sp" android:textStyle="bold"/>
item_price_detail.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:padding="16dp" android:orientation="horizontal" android:gravity="center_vertical"> <TextView android:id="@+id/tv_company" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:textSize="16sp"/> <TextView android:id="@+id/tv_fuel_type" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:textSize="16sp" android:gravity="center"/> <TextView android:id="@+id/tv_price" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:textSize="16sp" android:gravity="end"/> <TextView android:id="@+id/tv_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" android:paddingStart="8dp" android:textColor="#666"/> </LinearLayout>
5. 配置RecyclerView
最后在Activity/Fragment里初始化RecyclerView并设置Adapter:
// 假设你的RecyclerView id是rv_price_list val rvPriceList = findViewById<RecyclerView>(R.id.rv_price_list) rvPriceList.layoutManager = LinearLayoutManager(this) rvPriceList.adapter = PriceAdapter(heterogeneousList)
额外提示
- 如果需要按公司再分组(比如同一城市下先显示Bharat Petroleum的所有油品,再显示Indian Oil的),可以在分组城市后,再对每个城市的列表按company分组,然后依次添加公司标题Item和油品详情Item,这样就变成三层异构了。
- 解析JSON时可以用Moshi、Retrofit等其他库,根据你的项目习惯选择。
- 可以给RecyclerView添加分割线,让异构列表的层级更清晰。
内容的提问来源于stack exchange,提问作者Anand Gaur
相关产品推荐
相关产品推荐

