First. You cannot (I believe) have a val detailList:List<Detail>?
, you need a single (not a List) item.
So (1) add a new Class that embodies the List e.g. :-
data class DetailList(
val detailList: List<Detail>
)
and (2) in WeatherForecastEntity use :-
/* val detailList:List<Detail>? */
val detailList: DetailList?
- the original line has been commented out
So now you have a single item/variable/field that needs to be converted by a TypeConverter.
then (3) create a class such as (see note re placement/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)
}
}
- The
fromDetailList
function converts a DetailList
(a List<Detail>
) to a String
(a json string of the DetailList object, which embodies all the underlying objects such as Clouds, Sys, Main within the string). This is used when inserting into the database.
- The
toDetailList
function does the reverse and builds the DetailList
object (and the underlying objects) from the stored String
. This is used when extracting the data from the database.
- In both cases Room knows to use the respective TypeConverter (Room knows due to the Types used by the functions (i.e the Type passed and the Type returned)). You would always have a pair of functions (or many pairs within the class for different TypeConverters)
Then (4) add the following to the @Database
class after the @Database
annotation :-
@TypeConverters(DetailListTypeConverter::class)
Demo
For Example (as used to demo) :-
@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
}
}
}
- i.e. the @TypeConverters annotation has been added
- Note that for convenience/brevity
.allowMainThreadQueries()
has been used, so the demo runs on the main thread (not recommended for an App that will be distributed)
Now using your classes (Classes Sys, Clouds and Wind were created as they aren't included in the question, so they will very likely NOT reflect your code) and the following @Dao
class AllDao (to allow insertion and extraction in the demo):-
@Dao
abstract class AllDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
abstract fun insert(weatherForecastEntity: WeatherForecastEntity): Long
@Query("SELECT * FROM forecast")
abstract fun getAllForecasts(): List<WeatherForecastEntity>
}
Then using the following code in an activity to demonstrate that the above works :-
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)
}
}
- The above code will insert a new row each time it is run and then extract all the rows outputting some of the extracted data.
So after 3 runs the log includes :-
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
- the first 3 lines being from the TypeConverter showing that the json has been extracted.
- The subsequent lines showing that the data has been successfully extracted and that the
detailList
includes the detail (2 per row) (albeit identical data).
The database itself, as per Android Studio's App Inspector :-
