Custom Type
Persist non-primitive types in Room using TypeConverters or Embedded types.
Type Converter
Type converters are pairs of functions, annotated with @TypeConverter, that translate a single database column type to a Kotlin property type and back.
Typical uses:
- Map an
Instantto aLongfor a SQLiteintegercolumn. - Map a
Locationto aStringfor a SQLitetextcolumn. - Map a collection of
Stringto a singleString(e.g., CSV) for atextcolumn.
Type converters are strictly 1:1 (one property ↔ one column).
Setting Up a Type Converter
- Create any Kotlin class to hold converter functions.
- For each type pair, create two functions: A→B and B→A. If input is
null, returnnull. Ensure the round-trip preserves values. - Annotate both functions with
@TypeConverter. - Bring them into scope with
@TypeConverterson one of:
| @TypeConverters on… | Applies to… |
|---|---|
| RoomDatabase | everything in the database |
| Entity class | all properties in that entity |
| Entity property | that property only |
| DAO class | all DAO functions |
| DAO function | that function (all params) |
| DAO function parameter | that single parameter |
Example: an entity using converters for Instant, Location, and Set<String>:
@Entity(tableName = "record")
@TypeConverters(InstantTypeConverter::class, LocationTypeConverter::class, SetTypeConverter::class)
data class Record(
@PrimaryKey(autoGenerate = true)
val id: Long = 0,
val instant: Instant = Clock.System.now(),
val location: Location,
val tags: Set<String> = setOf()
) {
@Dao
interface SQL {
@Query("select * from record")
suspend fun select(): List<Record>
@Insert
suspend fun insert(entity: Record)
}
}
data class Location(val latitude: Double, val longitude: Double) {
constructor(location: Location) : this(location.latitude, location.longitude)
}InstantTypeConverter
SQLite does not have a native date/time type. The recommended approach is to store timestamps as the number of milliseconds since the Unix epoch (January 1, 1970, 00:00:00 UTC).
Instant has a toEpochMilliseconds() function that returns this value.
class InstantTypeConverter {
@TypeConverter
fun instantToLong(timestamp: Instant?) = timestamp?.toEpochMilliseconds()
@TypeConverter
fun longToInstant(timestamp: Long?) =
timestamp?.let { Instant.fromEpochMilliseconds(it) }
}With @TypeConverters(InstantTypeConverter::class) in scope, Room will persist Instant as a SQLite integer.
LocationTypeConverter
Persist a Location (latitude/longitude) as a single String in a text column (e.g., “latitude;longitude”):
A Location object contains a latitude, longitude, and perhaps other values (e.g., altitude). If we only care about the latitude and longitude, we could save those in the database in a single text column, so long as we can determine a good format to use for that string. One possibility is to have the two values separated by a semicolon.
The LocationTypeConverter class has a pair of functions designed to convert between a Location and a String:
class LocationTypeConverter {
@TypeConverter
fun locationToString(location: Location?) =
location?.let { "${it.latitude};${it.longitude}" }
@TypeConverter
fun stringToLocation(location: String?) = location?.let {
val pieces = location.split(';')
if (pieces.size == 2) {
try {
Location(pieces[0].toDouble(), pieces[1].toDouble())
} catch (e: Exception) {
null
}
} else {
null
}
}
}Estàs llegint una vista prèvia.
Inicia sessió per llegir l'article complet. Qualsevol compte obre 4 articles gratuïts al mes; l'alumnat i el professorat llegeixen les pàgines del seu curs sense límit.
Inicia sessió