如何解决Room不支持返回LiveData嵌套List或Map类型数据的问题
Room多层嵌套返回类型报错问题解决
报错详情
Room报错信息如下:
error: Not sure how to convert a Cursor to this method's return type (androidx.lifecycle.LiveData<java.util.List<java.util.List<com.example.shoppingapp.room.GroceryItems>>>). public abstract androidx.lifecycle.LiveData<java.util.List<java.util.List<com.example.shoppingapp.room.GroceryItems>>> getAllGroceryItems();
Room本身不支持直接返回LiveData<List<List<itemElement>>>这类多层嵌套的集合类型,尝试返回LiveData<Map<String, List<GroceryItems>>>也会触发同类Cursor转换错误。
业务场景说明
- 存在两个Fragment,均通过RecyclerView展示列表:
- 第一个Fragment展示
List<ItemFirstFragment> - 点击第一个Fragment的列表元素后,将对应id和名称传递到第二个Fragment,需要从
List<List<GroceryItem>>结构中取出指定下标的List<GroceryItem>在第二个Fragment展示,对应逻辑:list[positionFromFirstFragment] // 从List<List<GroceryItem>>取出对应下标List<GroceryItem>
- 第一个Fragment展示
原实体类定义
用到的GroceryItems实体类代码如下:
package com.example.shoppingapp.room import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey @Entity(tableName = "grocery_items") data class GroceryItems ( @ColumnInfo(name = "itemName") var itemName: String, @ColumnInfo(name = "itemQuantity") var itemQuantity: Int, @ColumnInfo(name = "itemPrice") var itemPrice: Int ) { @PrimaryKey(autoGenerate = true) var id: Int? = null }
解决方案
方案1:使用Room一对多关系映射(推荐)
步骤1:新增父级分类实体
对应第一个Fragment展示的列表项,新增父级分类实体类:
@Entity(tableName = "grocery_categories") data class GroceryCategory( @PrimaryKey(autoGenerate = true) val categoryId: Int = 0, val categoryName: String )
步骤2:改造子实体添加外键
修改GroceryItems实体,新增关联父级分类的外键字段:
@Entity( tableName = "grocery_items", foreignKeys = [ForeignKey( entity = GroceryCategory::class, parentColumns = ["categoryId"], childColumns = ["categoryId"], onDelete = ForeignKey.CASCADE )] ) data class GroceryItems ( val categoryId: Int, // 关联父分类id @ColumnInfo(name = "itemName") var itemName: String, @ColumnInfo(name = "itemQuantity") var itemQuantity: Int, @ColumnInfo(name = "itemPrice") var itemPrice: Int ) { @PrimaryKey(autoGenerate = true) var id: Int? = null }
步骤3:新增一对多数据封装类
data class CategoryWithItems( @Embedded val category: GroceryCategory, @Relation( parentColumn = "categoryId", entityColumn = "categoryId" ) val groceryItems: List<GroceryItems> )
步骤4:定义DAO查询方法
直接返回LiveData<List<CategoryWithItems>>,Room会自动完成一对多数据的映射:
@Query("SELECT * FROM grocery_categories") fun getAllCategoriesWithItems(): LiveData<List<CategoryWithItems>>
跳转第二个Fragment时可直接传递选中分类的id,单独查询对应分类下的商品列表,性能更高:
@Query("SELECT * FROM grocery_items WHERE categoryId = :categoryId") fun getItemsByCategoryId(categoryId: Int): LiveData<List<GroceryItems>>
方案2:自行转换查询结果
如果不想改动现有表结构,可先让DAO返回单层的LiveData<List<GroceryItems>>,拿到数据后在ViewModel层按照业务规则自行分组为嵌套List或者Map结构即可。
内容的提问来源于stack exchange,提问作者chrisu.chrisu
相关产品推荐
相关产品推荐

