gpt4 book ai didi

java - 有没有办法覆盖 Android Room 实体构造函数?

转载 作者:行者123 更新时间:2023-12-02 09:40:31 26 4
gpt4 key购买 nike

我正在尝试覆盖 Android Room 实体对象的创建。

我想在从数据库实例化对象时初始化其他属性。我关注了Android Room实体Documentation

我使用的 Room 版本:room-runtime:2.1.0

我尝试在 setter 和构造函数中记录消息,但没有任何消息出现在我的 LogCat 中。

@Entity
// EDIT AFTER SOLUTION. You have to do this in the class that room is using to query the data, in my case it was a viewModel.
public class Client /* or ImportantInformationsClientViewModel */ {

@SerializedName("azEMail")
private String azEMail;

@SerializedName("azFirstName")
private String azFirstName;

@SerializedName("azMobile")
private String azMobile;

@Ignore
private MyMobileObject;

public Client(String azEMail, String azFirstName, String azMobile) {
Log.d("CLIENT_LOG", "Constructor is instanciated"); // Never logged
this.azEMail = azEMail;
this.azFirstName = azFirstName;
this.azMobile = azMobile;
// I would like to instantiate MyMobileObject each time this constructor (or the setter) is called
}

public String getAzEMail() {
return azEMail;
}

public void setAzEMail(String azEMail) {
Log.d("CLIENT_LOG", "Setter is called"); // Never Logged
this.azEMail = azEMail;
}

public String getAzFirstName() {
return azFirstName;
}

public void setAzFirstName(String azFirstName) {
this.azFirstName = azFirstName;
}

public String getAzMobile() {
return azMobile;
}

public void setAzMobile(String azMobile) {
this.azMobile = azMobile;
// I would like to instantiate MyMobileObject each time this setter (or the constructor) is called
}

public String getAzName() {
return azName;
}

public void setAzName(String azName) {
this.azName = azName;
}

public void setupObject() {
// One ugly way to fix the problem is to call this method when my object is created. I want to avoid this.
}
}

我发现解决该问题的一种方法是在对象中创建一个 setupObject 方法,并在从查询中获得该对象后调用此方法。它确实有效,但是有点难看,而且毫无意义地增加了更多的代码和复杂性。我正在努力避免这种情况。

是否可以添加在 android-room 创建对象时调用的特定代码?例如 AzMobile setter 中的例子?

room 如何实例化对象?这些属性是私有(private)的,访问它的唯一方法是通过 LogCat 中似乎没有调用的 setter。

回答后编辑

关于空间的棘手问题是了解我们实体的实现是如何工作的。

我的实体是一个客户端对象,但是当我从数据库进行查询时,我是使用 ViewModel 进行查询(类似于重要信息客户端 View 模型)我认为,由于 Room 只知道客户端实体,它会将我的 ViewModel 包装在实体中,并从实体中神奇地构建它(这不是那么愚蠢.. 这对我来说很有意义..)

检查我的 android-room 生成的 DAO 实现 (ScheduleDao_Impl) 后,我发现 room 实际上是直接构建 ViewModel 对象。我刚刚在 ViewModel 中移动了我的属性和函数,一切正常。

如果我必须列出需要了解的重要事项:

  • android-room仅使用@Entity来构建SQLite数据库中的对象模型,不使用@Entity来构建查询对象

    <
  • android-room 将在您构建应用程序时生成 YourDao_Impl.java 对象,您可以通过 CTRL + MAJ + F 访问它

  • android-room 将需要 ctor 或 setter 或两者(它只需要访问所有属性)

  • 花几个小时检查所有 ApplicationDatabase_Impl 文件将帮助您了解 android-room 的工作原理以及所有内容如何包装在一起。

最佳答案

更新(澄清后)

我很惊讶你没有看到这些电话。因为通过检查生成的 DAO,我可以看到 ROOM 正在做什么。它通过 SQLite 进行查询,并使用游标在结果中移动,调用 CTOR。

DAO 是在编译时生成的,因此在构建项目后,如果您在 macOS 中,请点击“ctrl-shift-F”或“cmd”(或者您的 Android 工作室用于查找的任何快捷方式)并尝试找到您的 DAO 的名称。你会看到YourDaoYourDao_Impl() -> 这是自动生成的。 :)打开它。

这是我的 DAO 实现之一的简化​​复制/粘贴:

“型号”是RealTimeData 。道法是loadAll()它返回 List<RealTimeData>显然。

这是方法(删除了最不相关的内容):我内联添加了注释。

  @Override
public List<RealTimeData> loadAll() {
/// PREPARE THE QUERY, SQL, AND CURSOR.
final String _sql = "SELECT * FROM realtime_data";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
final Cursor _cursor = __db.query(_statement);
try {
// OBTAIN THE COLUMN NAMES FROM THE TABLE DEFINITION
final int _cursorIndexOfId = _cursor.getColumnIndexOrThrow("id");
final int _cursorIndexOfJsonData = _cursor.getColumnIndexOrThrow("json_data");
final int _cursorIndexOfIsSent = _cursor.getColumnIndexOrThrow("is_sent");
final int _cursorIndexOfDeviceId = _cursor.getColumnIndexOrThrow("device_id");
final int _cursorIndexOfDateCreated = _cursor.getColumnIndexOrThrow("date_created");

// THIS WILL STORE THE RESULTS
final List<RealTimeData> _result = new ArrayList<RealTimeData>(_cursor.getCount());

// ITERATE IT, CREATE A "RealTimeData" AND POPULATE IT.
while(_cursor.moveToNext()) {
final RealTimeData _item;
final String _tmpId;
_tmpId = _cursor.getString(_cursorIndexOfId);
final String _tmpJsonData;
_tmpJsonData = _cursor.getString(_cursorIndexOfJsonData);
final Date _tmpDateCreated;
final Long _tmp;
// SOME THINGS NEED EXTRA CHECKS, THIS IS A DATE FIELD, STORED AS "long", SO NULL MUST BE CHECKED OR THE DATE CONVERTER WOULD THROW NPE
if (_cursor.isNull(_cursorIndexOfDateCreated)) {
_tmp = null;
} else {
_tmp = _cursor.getLong(_cursorIndexOfDateCreated);
}
// IT'S A DATE, SO CALL THE DATE CONVERTER (supplied via the @TypeConverter() annotation)
_tmpDateCreated = DateConverter.toDate(_tmp);


// BAM: INVOKE THE CTOR
_item = new RealTimeData(_tmpId,_tmpJsonData,_tmpDateCreated);

// NOW USE SETTERS FOR THE "OTHERS"
final boolean _tmpIsSent;
final int _tmp_1;
_tmp_1 = _cursor.getInt(_cursorIndexOfIsSent);
_tmpIsSent = _tmp_1 != 0;
_item.setSent(_tmpIsSent);
final String _tmpDeviceId;
_tmpDeviceId = _cursor.getString(_cursorIndexOfDeviceId);
_item.setDeviceId(_tmpDeviceId);

// AND ADD IT TO THE RESULTS...
_result.add(_item);
}

// YOU GET THIS ONE :p
return _result;
} finally {
_cursor.close();
_statement.release();
}
}

“本例中的模型”看起来完全像这样:

Entity(tableName = "realtime_data")
public class RealTimeData {

@PrimaryKey
@NonNull
private String id;

@ColumnInfo(name = "json_data")
private String jsonData;

@ColumnInfo(name = "is_sent")
private boolean isSent;

@ColumnInfo(name = "device_id")
private String deviceId;

@ColumnInfo(name = "date_created")
private Date dateCreated;

@Ignore
RealTimeData(@NonNull final String jsonData, @NonNull final Date dateCreated) {
id = UUID.randomUUID().toString();
this.jsonData = jsonData;
this.dateCreated = dateCreated;
}

RealTimeData(@Nonnull final String id, final String jsonData, final Date dateCreated) {
this.id = id;
this.jsonData = jsonData;
this.dateCreated = dateCreated;
}

String getJsonData() {
return jsonData;
}

@Nonnull
public String getId() {
return id;
}

public boolean isSent() {
return isSent;
}

public String getDeviceId() {
return deviceId;
}

public Date getDateCreated() {
return dateCreated;
}

public void setSent(final boolean sent) {
isSent = sent;
}

public void setDeviceId(final String deviceId) {
this.deviceId = deviceId;
}
}

所以你的意思是,当 ROOM 实例化它时,你的 ctor 没有被调用?

更新结束

对于有值(value)的东西,您可以拥有额外的构造函数(前提是它们不遮盖空的公共(public)构造函数和/或采用所有字段的构造函数)。添加 @Ignore属性。

例如:(为了保持一致性,我从哈迪克的答案中窃取了他的样本)

@Entity
public class User {
@PrimaryKey
private final int uid;
private String name;
@ColumnInfo(name = "last_name")
private String lastName;

public User(int uid) {
this.uid = uid;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}

@Ignore
User(String firstName, String lastName) {
this.lastName = lastname;
this.name = firstName;
}
}

这可行,但请记住,如果您不使用“自动生成”主键,则需要先为该字段分配一个主键,然后 Room 才会接受该主键进行插入或类似操作。

这就是你想做的事吗?

关于java - 有没有办法覆盖 Android Room 实体构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57112805/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com