首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有没有一种方法可以覆盖Android实体构造器?

有没有一种方法可以覆盖Android实体构造器?
EN

Stack Overflow用户
提问于 2019-07-19 12:45:51
回答 2查看 2.1K关注 0票数 0

我试图重写Android实体对象的创建。

当从数据库实例化对象时,我希望初始化其他属性。我跟踪了Android实体文档

我使用的是房间版本:room-runtime:2.1.0

我试图在setter中和构造函数中记录消息,但是没有一个消息出现在我的LogCat中。

代码语言:javascript
复制
@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创建对象时,可以添加特定的代码吗?比如在AzMobile设置器中?

那么房间是如何实例化对象的呢?属性是私有的,访问它的唯一方法是通过LogCat中似乎不被调用的setter。

答案后编辑

有空间的棘手之处在于理解我们实体的实现是如何工作的。

我的实体是客户端对象,但当我从DB执行查询时,我使用ViewModel (类似于ImportantInformationsClientViewModel)执行查询,我认为,由于Room只知道客户端实体,它会将我的ViewModel封装在实体中,并从该实体神奇地构建它(这并不愚蠢)。对我来说很有意义..。)

在检查了我的android生成的DAO实现(ScheduleDao_Impl)之后,我看到这个房间实际上是直接构建ViewModel对象的。我只是在ViewModel中移动了我的属性和函数,一切都成功了。

如果我必须列出要知道的重要事情:

  • android-room只使用@Entity在SQLite数据库中构建对象模型,而不使用@实体构建查询对象
  • 当您构建应用程序时,android-room将生成一个YourDao_Impl.java对象,您可以使用CTRL + MAJ + F访问它。
  • android-room将需要ctor或setter或两者都需要(它只需要访问所有属性)
  • 花几个小时来检查所有的ApplicationDatabase_Impl文件将帮助你理解安卓房间是如何工作的,以及所有的东西是如何包装在一起的。
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-07-19 13:07:37

最新情况(澄清后)

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

DAO是在编译时生成的,所以在构建项目之后,如果您在macOS (或者安卓工作室使用的任何快捷方式查找),点击“ctrl F”或"cmd“,然后尝试查找DAO的名称。您将看到YourDaoYourDao_Impl() -> --这是自动生成的。)打开它。

这是来自我的DAOs实现之一的一个简化的副本/粘贴:

“模型”是RealTimeData。Dao的方法是loadAll(),它显然返回一个List<RealTimeData>

下面是一个方法(删除了最不相关的内容):我在行中添加了注释。

代码语言:javascript
复制
  @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();
    }
  }

“这种情况下的模型”看起来就像这样:

代码语言:javascript
复制
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;
    }
}

所以你的意思是,当房间实例化这个,你的ctor就不会被调用?

更新结束

对于价值所在,您可以拥有额外的构造函数(前提是它们不隐藏空的公共构造函数和/或包含所有字段的构造函数)。添加@Ignore属性。

例句:(我从哈迪克的答案中偷了他的样本,以保证一致性)

代码语言:javascript
复制
@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将接受它的插入或类似。

这就是你想做的吗?

票数 1
EN

Stack Overflow用户

发布于 2019-07-19 12:51:33

每个实体必须有一个no-arg构造函数或一个参数匹配字段(基于类型和名称)的构造函数。构造函数不必以参数的形式接收所有字段,但如果字段未传递给构造函数,则它应该是公共的或具有公共设置器的。如果匹配的构造函数可用,Room将始终使用它。

例如。

代码语言:javascript
复制
@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;
   }
 }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57112805

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档