You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Room自定义构造器报错:实体与POJO需可用公共构造器

Room实体类构造器与@Ignore注解问题解决

问题背景

在Android Kotlin项目中使用Room创建数据库表实体,编写了Bike实体类并嵌入Sensor类,但编译时出现以下错误:

  • Bike类:Entities and POJOs must have a usable public constructor
  • Sensor类:同样报构造器不可用的错误

移除Sensor类的@Ignore注解可正常编译,但需要保留这些注解来忽略不需要持久化的字段和方法。尝试将Bike类字段初始化移至次级构造器或init{}块后仍无法解决问题。

相关代码

Bike实体类

@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
}

Sensor类

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
    }
}

Dao接口

@Dao
interface BikeDao {

    @Insert
    fun insertBike(bike: Bike)

    @Delete
    fun deleteBike(bike: Bike)

    @Query("SELECT * FROM bikes")
    fun selectBikes() : LiveData<List<Bike>>
}

编译错误信息

Bike类错误

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]

Sensor类错误

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]

错误原因

  1. Sensor类问题:主构造器参数_id、_lowPressureTh与类内字段id、lowPressureTh名称不匹配,Room按名称匹配构造器参数和字段,下划线导致无法识别对应关系。
  2. Bike类问题:主构造器中的sensorFid、sensorRid等参数是用来初始化嵌入的Sensor对象的,并非Bike类的直接持久化字段,Room无法识别这种间接初始化的参数,找不到匹配的字段。

修复方案

1. 修复Sensor类

调整主构造器参数名称与字段一致,去掉下划线,让Room能正确匹配参数和字段,同时保留@Ignore注解忽略不需要持久化的内容:

class Sensor(id: Int, lowPressureTh: Int) {
    var id: Int = id
    var lowPressureTh: Int = lowPressureTh

    @Ignore
    var pressureBar: Int? = null
    @Ignore
    var temperatureC: Int? = null
    @Ignore
    var battery: Byte? = null

    // 带测量数据的次级构造器
    constructor(id: Int, lowPressureTh: Int, pressureBar: Int?, temperatureC: Int?, battery: Byte?) : this(id, lowPressureTh) {
        this.pressureBar = pressureBar
        this.temperatureC = temperatureC
        this.battery = battery
    }

    @Ignore
    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
    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
    }
}

2. 修复Bike类

提供Room可识别的构造器,参数对应所有需要持久化的字段(包括嵌入Sensor的字段),或者直接用主构造器定义所有持久化字段:

@Entity(tableName = "bikes")
class Bike(
    var name: String,
    var appearance: Int,
    @Embedded(prefix = "senF_")
    val sensorFront: Sensor,
    @Embedded(prefix = "senR_")
    val sensorRear: Sensor,
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0 // autoGenerate=true时,默认0即可,Room会自动生成主键值
) {
    // 保留原业务逻辑的次级构造器
    constructor(
        name: String,
        appearance: Int,
        id: Int,
        sensorFid: Int,
        sensorRid: Int,
        lowPressThreshF: Int,
        lowPressThreshR: Int
    ) : this(
        name,
        appearance,
        Sensor(sensorFid, lowPressThreshF),
        Sensor(sensorRid, lowPressThreshR),
        id
    )
}

修复原理

  • Sensor类:主构造器参数与字段名称一致后,Room能正确映射参数到字段,@Ignore标记的字段和方法会被Room跳过,不参与数据库持久化逻辑。
  • Bike类:主构造器直接定义了所有需要持久化的字段(包括嵌入的Sensor对象),Room可以直接识别这些字段并生成对应的数据库表结构;次级构造器保留了原有的业务初始化方式,不影响Room的映射逻辑。

内容的提问来源于stack exchange,提问作者Michal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 00:12:33