【问题标题】:How to make Android Room ignore a constructor of a library class?如何让 Android Room 忽略库类的构造函数?
【发布时间】:2021-08-10 11:57:34
【问题描述】:

我正在尝试将 POJO 嵌入到 Android Room 实体中。但是,这样做时,我收到以下错误(类名已更改):

  • 有多个好的构造函数,Room 会选择无参数构造函数。您可以使用 @Ignore 注释来消除不需要的构造函数。 - LibraryPojo
  • 找不到字段的设置器。 - LibraryPojo 中的 timeOfCreation

这是我要嵌入的 POJO:

public class LibraryPojo {
    private final long timeOfCreation;

    public LibraryPojo(long timeOfCreation) {
        this.timeOfCreation = timeOfCreation;
    }

    public LibraryPojo() {
        this(System.currentTimeMillis());
    }

    public long getTimeOfCreation() {
        return timeOfCreation;
    }
}

在我的实体中,我正在这样做:

@Embedded
final LibraryPojo pojo;

如果我删除无参数构造函数,它工作正常。 问题是,我不能将@Ignore 注解添加到这个构造函数中,因为这个类是普通Java 库的一部分,因此不能访问android 类。

由于关注点分离,我不想更改库类(让数据库工作不是库的工作!)。 我也不想继承LibraryPojo 以隐藏到超类构造函数,因为那会迫使我嵌入子类。这反过来又阻止了我将 LibraryPojo 的实例分配给该字段,从而迫使我每次都创建子类的实例。

难道没有更好的方法来隐藏 Room 中的构造函数而不更改声明它们的类吗?

【问题讨论】:

  • Room 不允许忽略 no-arg 构造函数,因此您必须在一个 arg 构造函数 @Ignore public LibraryPojo(long timeOfCreation) { this.timeOfCreation = timeOfCreation; } 之前添加 @Ignore
  • 如我的问题所述,我无法将@Ignore 添加到LibraryPojo 类,因为它是普通Java 库的一部分,因此无法访问android 框架类。

标签: java android android-room


【解决方案1】:

如果我删除无参数构造函数,它工作正常。问题是,我无法在此构造函数中添加 @Ignore 注释,因为此类是普通 Java 库的一部分,因此无法访问 android 类。

正如我的问题所述,我无法将 @Ignore 添加到 LibraryPojo 类,因为它是普通 Java 库的一部分,因此无法访问 android 框架类。

您可以在 LibraryPojo 类中使用@Ignore。

这是一个演示在 POJO 中使用 @Ignore 的工作示例,我认为您要完成的工作:-

LibraryPojo :-

public class LibraryPojo {

    long timeOfCreation;

    LibraryPojo() {
        this.timeOfCreation = System.currentTimeMillis();
    }

    @Ignore
    LibraryPojo(long timeOfCreation) {
        this.timeOfCreation = timeOfCreation;
    }

    public long getTimeOfCreation() {
        return timeOfCreation;
    }

    public void setTimeOfCreation(long timeOfCreation) {
        this.timeOfCreation = timeOfCreation;
    }
}

嵌入 LibraryPojo 的实体 LibraryExtended(本身带有 @Ignored 构造函数):-

@Entity
class LibraryExtended {
    @PrimaryKey
    Long id;
    @Embedded
    LibraryPojo pojo;
    String name;

    LibraryExtended(){}

    @Ignore
    LibraryExtended(LibraryPojo pojo, String name) {
        this.pojo = pojo;
        this.name = name;
        this.id  = -1L;
    }
}

一个基本的 Dao LibraryDao :-

@Dao
abstract class LibraryDao {

    @Insert
    abstract long insert(LibraryExtended le);

    @Query("SELECT * FROM libraryextended")
    abstract List<LibraryExtended> getAll();

}

一个基本的@Database 类TheDatabase :-

@Database(entities = {LibraryExtended.class}, version = 1)
abstract class TheDatabase extends RoomDatabase {
    abstract LibraryDao getLibraryDao();

    private static volatile TheDatabase instance = null;

    public static TheDatabase getInstance(Context context) {
        if (instance == null) {
            instance = Room.databaseBuilder(context,TheDatabase.class,"library.db")
                    .allowMainThreadQueries()
                    .build();
        }
        return instance;
    }
}

最后从一个activity访问数据库,存储一行然后提取该行:-

public class MainActivity extends AppCompatActivity {

    TheDatabase db;
    LibraryDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        db = TheDatabase.getInstance(this);
        dao = db.getLibraryDao();
        LibraryExtended le = new LibraryExtended(new LibraryPojo(0L),"mylibrarryextended");
        dao.insert(le);
        for(LibraryExtended l: dao.getAll()) {
            Log.d("LIBINFO","Name is " + l.name + " id is " + String.valueOf(l.id));
        }
    }
}

结果

日志包括:-

D/LIBINFO: Name is mylibrarryextended id is -1

【讨论】:

  • 问题是,我必须在 LibraryPojo 类中导入 androidx.room.Ignore 才能工作。这意味着,该库将在其类路径中需要 androidx.room:room-common。但这不会破坏 android 框架之外的库吗?因为是的,LibraryPojo 在纯 Java 环境中使用时也必须工作!
【解决方案2】:

Kotlin 中忽略无参数构造函数的最简单方法是: @忽视 构造函数():this(0)

例如:

@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(@PrimaryKey(autoGenerate = true)
                      var nightId: Long = 0L,

                      @ColumnInfo(name = "start_time_milli")
                      val startTimeMilli: Long =  System.currentTimeMillis(),

                      @ColumnInfo(name = "end_time_milli")
                      var endTimeMilli: Long = startTimeMilli,

                      @ColumnInfo(name = "quality_rating")
                      var sleepQuality: Int = -1
){
    @Ignore
    constructor() : this(0)
}

这应该可以解决问题:)

【讨论】:

  • 除了我需要 Java 中的解决方案这一事实之外,这似乎也无法解决 我无法将 @Ignore 添加到 POJO 类的问题,因为它不是android 库的一部分。
  • 最终的解决方案是我不得不将 Kotlin 插件降级到类路径 "org.jetbrains.kotlin:kotlin-gradle-plugin: 1.4.32 没有@Ignore 的所有工作
猜你喜欢
  • 1970-01-01
  • 2020-11-07
  • 2017-03-08
  • 1970-01-01
  • 2020-10-18
  • 2018-01-30
  • 1970-01-01
  • 2021-04-29
  • 2014-02-11
相关资源
最近更新 更多