android - 为房间数据库创建类型转换器的问题
问题描述
嘿伙计们,我正在尝试创建一个有空间的数据库,并且我有一个数据类作为实体,如下所示:
@Entity(tableName = "forecast")
data class WeatherForecastEntity(
@PrimaryKey(autoGenerate = false)
val id:Int?,
val city:String?,
val country:String?,
val timeZone:Int?,
val sunrise: Int?,
val sunset: Int?,
val detailList:List<Detail>?
)
如您所见,我有一个名为 detailList 的值,它是一个名为 Detail 的数据类的列表,如下所示:
data class Detail(
val clouds: Clouds?,
val dt: Int?,
val dt_txt: String?,
val main: Main?,
val pop: Int?,
val sys: Sys?,
val visibility: Int?,
val weather: List<Weather>?,
val wind: Wind?
)
在这个类中,我有一些其他数据类的实例,例如天气值,它是天气数据类的列表,如下所示:
data class Weather(
val description: String?,
val icon: String?,
val id: Int?,
val main: String?
)
或 main 是另一个名为 Main 的数据类的实例,如下所示:
data class Main(
val feels_like: Double?,
val grnd_level: Int?,
val humidity: Int?,
val pressure: Int?,
val sea_level: Int?,
val temp: Double?
)
当我运行我的应用程序时,我收到一个错误,说我必须创建一个类型转换器,我真的不知道我应该如何处理这些具有彼此实例的许多数据类。如果您能帮助我,我将不胜感激。顺便说一句,我在我的应用程序中使用了 RxJava 和 Gson。
解决方案
第一的。你不能(我相信)有一个val detailList:List<Detail>?
,你需要一个(不是列表)项目。
所以(1)添加一个体现列表的新类,例如:-
data class DetailList(
val detailList: List<Detail>
)
( 2)在 WeatherForecastEntity 中使用:-
/* val detailList:List<Detail>? */
val detailList: DetailList?
- 原行已被注释掉
所以现在你有一个需要由 TypeConverter 转换的项目/变量/字段。
然后(3)创建一个类,例如(参见注释replacement/scope):-
class DetailListTypeConverter {
@TypeConverter
fun toDetailList(value: String): DetailList {
Log.d("DBINFO_FROMJSON","Extracted>>${value}") /* just for demonstration */
return Gson().fromJson(value,DetailList::class.java)
}
@TypeConverter
fun fromDetailList(value: DetailList): String {
return Gson().toJson(value)
}
}
- 该
fromDetailList
函数将(a )转换为( DetailList 对象的 json 字符串,该字符串包含所有底层对象,例如字符串中的 Clouds、Sys、Main)。这在插入数据库时使用。DetailList
List<Detail>
String
- 该
toDetailList
函数执行相反的操作并DetailList
从存储的String
. 这在从数据库中提取数据时使用。 - 在这两种情况下,Room 都知道使用各自的TypeConverter(Room 知道由于函数使用的类型(即传递的类型和返回的类型))。您将始终拥有一对函数(或类中的许多对用于不同的 TypeConverters)
然后(4)在注释后将以下内容添加到@Database
类中:-@Database
@TypeConverters(DetailListTypeConverter::class)
- 注意参见/阅读https://developer.android.com/reference/androidx/room/TypeConverters,关于 TypeConverters 的位置/范围
演示
例如(用于演示):-
@Database(entities = [WeatherForecastEntity::class],version = 1)
@TypeConverters(DetailListTypeConverter::class) /*<<<<<<<<<< ADDED >>>>>>>>>>*/
abstract class TheDatabase: RoomDatabase() {
abstract fun getAllDao(): AllDao
companion object {
private var instance: TheDatabase? = null
fun getInstance(context: Context): TheDatabase {
if (instance == null) {
instance = Room.databaseBuilder(
context,
TheDatabase::class.java,
"weather.db"
)
.allowMainThreadQueries()
.build()
}
return instance as TheDatabase
}
}
}
- 即添加了@TypeConverters 注解
- 请注意,为了方便/简洁
.allowMainThreadQueries()
已经使用,所以演示在主线程上运行(不推荐用于将要分发的应用程序)
现在使用您的类(创建类Sys、Clouds和Wind,因为它们不包含在问题中,因此它们很可能不会反映您的代码)和以下@Dao
类AllDao (允许在演示中插入和提取):-
@Dao
abstract class AllDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
abstract fun insert(weatherForecastEntity: WeatherForecastEntity): Long
@Query("SELECT * FROM forecast")
abstract fun getAllForecasts(): List<WeatherForecastEntity>
}
然后在活动中使用以下代码来证明上述工作:-
class MainActivity : AppCompatActivity() {
lateinit var db: TheDatabase
lateinit var dao: AllDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = TheDatabase.getInstance(this)
dao = db.getAllDao()
dao.insert(createSomeData())
for(wf: WeatherForecastEntity in dao.getAllForecasts()) {
Log.d("DBINFO","City is ${wf.city}")
for (dl: Detail in wf.detailList!!.detailList) {
Log.d("DBINFO_DETAIL","Detail is ${dl.dt} Clouds is ${dl.clouds!!.name}")
}
}
}
fun createSomeData(): WeatherForecastEntity {
val dtlList: ArrayList<Detail> = arrayListOf()
val dtl1 = Detail(
clouds = Clouds(name = "Cirrus", value = 10.2),
dt = 10,
dt_txt = "The dt for dt1",
main = Main(feels_like = 1.1,grnd_level = 15, humidity = 65,sea_level = 100,pressure = 14,temp = 30.24),pop = 23000,visibility = 300,
weather = listOf(Weather(description = "wet","weticon",0,"wet")),
sys = Sys("sysname",10.333),
wind = Wind(22.5,10.23)
)
val dtl2 = dtl1
dtlList.add(dtl1)
dtlList.add(dtl2)
val detailList = DetailList(dtlList)
return WeatherForecastEntity(null,"London","England",0,100,100,detailList)
}
}
- 上面的代码将在每次运行时插入一个新行,然后提取所有输出一些提取数据的行。
所以在 3 次运行后,日志包括:-
2021-09-18 08:19:33.825 D/DBINFO_FROMJSON: Extracted>>{"detailList":[{"clouds":{"name":"Cirrus","value":10.2},"dt":10,"dt_txt":"The dt for dt1","main":{"feels_like":1.1,"grnd_level":15,"humidity":65,"pressure":14,"sea_level":100,"temp":30.24},"pop":23000,"sys":{"name":"sysname","value":10.333},"visibility":300,"weather":[{"description":"wet","icon":"weticon","id":0,"main":"wet"}],"wind":{"direction":22.5,"speed":10.23}},{"clouds":{"name":"Cirrus","value":10.2},"dt":10,"dt_txt":"The dt for dt1","main":{"feels_like":1.1,"grnd_level":15,"humidity":65,"pressure":14,"sea_level":100,"temp":30.24},"pop":23000,"sys":{"name":"sysname","value":10.333},"visibility":300,"weather":[{"description":"wet","icon":"weticon","id":0,"main":"wet"}],"wind":{"direction":22.5,"speed":10.23}}]}
2021-09-18 08:19:33.858 I/chatty: uid=10200(a.a.so69210605kotlinroomgsontypeconverter) identical 4 lines
2021-09-18 08:19:33.864 D/DBINFO_FROMJSON: Extracted>>{"detailList":[{"clouds":{"name":"Cirrus","value":10.2},"dt":10,"dt_txt":"The dt for dt1","main":{"feels_like":1.1,"grnd_level":15,"humidity":65,"pressure":14,"sea_level":100,"temp":30.24},"pop":23000,"sys":{"name":"sysname","value":10.333},"visibility":300,"weather":[{"description":"wet","icon":"weticon","id":0,"main":"wet"}],"wind":{"direction":22.5,"speed":10.23}},{"clouds":{"name":"Cirrus","value":10.2},"dt":10,"dt_txt":"The dt for dt1","main":{"feels_like":1.1,"grnd_level":15,"humidity":65,"pressure":14,"sea_level":100,"temp":30.24},"pop":23000,"sys":{"name":"sysname","value":10.333},"visibility":300,"weather":[{"description":"wet","icon":"weticon","id":0,"main":"wet"}],"wind":{"direction":22.5,"speed":10.23}}]}
2021-09-18 08:19:33.871 D/DBINFO: City is London
2021-09-18 08:19:33.871 D/DBINFO_DETAIL: Detail is 10 Clouds is Cirrus
2021-09-18 08:19:33.871 D/DBINFO_DETAIL: Detail is 10 Clouds is Cirrus
2021-09-18 08:19:33.871 D/DBINFO: City is London
2021-09-18 08:19:33.871 D/DBINFO_DETAIL: Detail is 10 Clouds is Cirrus
2021-09-18 08:19:33.871 D/DBINFO_DETAIL: Detail is 10 Clouds is Cirrus
2021-09-18 08:19:33.872 D/DBINFO: City is London
2021-09-18 08:19:33.872 D/DBINFO_DETAIL: Detail is 10 Clouds is Cirrus
2021-09-18 08:19:33.872 D/DBINFO_DETAIL: Detail is 10 Clouds is Cirrus
- 前 3 行来自 TypeConverter,表明 json 已被提取。
- 随后的行显示数据已成功提取并且
detailList
包括详细信息(每行 2 个)(尽管数据相同)。
数据库本身,根据 Android Studio 的 App Inspector :-
推荐阅读
- java - 在android手机上解析logcat输出
- java - 在android中使用socket.io时如何在运行时获取视图?
- protractor - 如何在分页列表中导航,直到找到带有 Serenity-JS 的文本?
- perl - Moose 变量名称可能不包含 :: at
- wordpress - 试图让 Wordpress ACF 包含来自 YouTube 或 Vimeo 的视频,但我收到 500 错误
- wpf - 您好,我需要设置依赖属性更改监听器
- sql-server - 使用 Entity Framework 和 linq 查询 SQL Server 视图非常慢
- php - 请求属性在构造中返回 null
- python - PySpark RDD SortByKey() Not Working Properly
- python - 在 Visual Studio Code 中将焦点切换到 Jupyter (IPython) 终端