I would like to create an entity of a table using room in Android Kotlin project.
A code of a class I want to combine to entity:
@Entity(tableName = "bikes")
class Bike(name: String, appearance: Int, id: Int, sensorFid: Int, sensorRid: Int, lowPressThreshF: Int, lowPressThreshR: Int) {
var appearance: Int = appearance
var name: String = name
@Embedded(prefix = "senF_")
val sensorFront: Sensor = Sensor(sensorFid, lowPressThreshF)
@Embedded(prefix = "senR_")
val sensorRear: Sensor = Sensor(sensorRid, lowPressThreshR)
@PrimaryKey(autoGenerate = true)
val id: Int = id
}
When I try to compile the code I get an error:
Entities and POJOs must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type). Tried the following constructors but they failed to match: Bike(java.lang.String,int,int,int,int,int,int) -> [param:name -> matched field:name, param:appearance -> matched field:appearance, param:id -> matched field:id, param:sensorFid -> matched field:unmatched, param:sensorRid -> matched field:unmatched, param:lowPressThreshF -> matched field:unmatched, param:lowPressThreshR -> matched field:unmatched]
That's the Sensor class I'm embedding:
class Sensor (_id: Int, _lowPressureTh: Int) {
var id: Int
var lowPressureTh: Int
@Ignore
var pressureBar: Int?
@Ignore
var temperatureC: Int?
@Ignore
var battery: Byte?
init {
id = _id
lowPressureTh = _lowPressureTh
pressureBar = null
temperatureC = null
battery = null
}
constructor(id: Int, lowPressureTh: Int, pressureBar: Int?, temperatureC: Int?, battery: Byte?) : this(id, lowPressureTh)
@Ignore
public fun updateMeasurementFromAdvData(advData: List<Long>) {
pressureBar = decodeInt(advData[0].toInt())
temperatureC = decodeInt(advData[1].toInt())
battery = advData[2].toByte()
Log.d("Moje", "pressure:" + pressureBar.toString())
Log.d("Moje", "temp:" +temperatureC.toString())
Log.d("Moje", "bat:" +battery.toString())
}
@Ignore
private fun decodeInt(codedValue: Int) : Int {
val buffer = ByteBuffer.allocate(4)
buffer.putInt(codedValue)
buffer.order(ByteOrder.LITTLE_ENDIAN)
buffer.flip()
return buffer.int
}
@Ignore
public fun equalId(id3: Int, id2: Int, id1: Int): Boolean {
if (id3 <= 0xFF && id2 <= 0xFF && id1 <= 0xFF) {
return (id == id3.shl(16).or(id2.shl(8).or(id1)))
}
else {
return false
}
}
@Ignore
fun setToNullData() {
pressureBar = null
temperatureC = null
battery = null
}
}
For a sensor class I'm getting a similar error:
Entities and POJOs must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type). Tried the following constructors but they failed to match: Sensor(int,int) -> [param:_id -> matched field:unmatched, param:_lowPressureTh -> matched field:unmatched] Sensor(int,int,java.lang.Integer,java.lang.Integer,java.lang.Byte) -> [param:id -> matched field:sensorRear > id, param:lowPressureTh -> matched field:sensorRear > lowPressureTh, param:pressureBar -> matched field:unmatched, param:temperatureC -> matched field:unmatched, param:battery -> matched field:unmatched]
My Dao code:
@Dao
interface BikeDao {
@Insert
fun insertBike(bike: Bike)
@Delete
fun deleteBike(bike: Bike)
@Query("SELECT * FROM bikes")
fun selectBikes() : LiveData<List<Bike>>
}
If I remove @Ignore annotations from sensor class, it compiles.
How to make Room process constructors and @Ignore annotations correctly?
So far I've tried moving the initialization of Bike class fields into a secondary constructor or init{} block, the same error. I' ve got through a dozen of post on SO but I just can't get it...
All you properties that correspond with table columns must be in the constructor. If you want a constructor that uses other properties, then it has to be a secondary constructor. For example, you can write your first class like this (I moved id
to the front according to convention):
@Entity(tableName = "bikes")
data class Bike(
@PrimaryKey(autoGenerate = true)
val id: Int = id,
var appearance: Int,
var name: String,
@Embedded(prefix = "senF_")
val sensorFront: Sensor,
@Embedded(prefix = "senR_")
val sensorRear: Sensor
) {
constructor(id: Int, name: String, appearance: Int, sensorFid: Int, sensorRid: Int, lowPressThreshF: Int, lowPressThreshR: Int):
this(id, name, appearance, Sensor(sensorFid, lowPressThreshF), Sensor(sensorRid, lowPressThreshR))
}
Room will use the primary constructor. The secondary constructor has the properties you wanted, so that's the one you can use in your own code.
For the Sensor class, you can eliminate your secondary constructor and use default arguments. This will effectively generate two constructors, one with just the two non-ignored parameters that have no default, and one with all the parameters. Room will use the one with only the non-ignored properties. This also saves a lot of code.
data class Sensor(
var id: Int,
var lowPressureTh: Int,
@Ignore
var pressureBar: Int? = null,
@Ignore
var temperatureC: Int? = null,
@Ignore
var battery: Byte? = null
) {
@Ignore
public fun updateMeasurementFromAdvData(advData: List<Long>) {
// The rest of your class...
}