是否可以在选定的房间数据库 Dao 列上启用/禁用转换?



目前,我们有以下数据库表

@Entity(
tableName = "note"
)
public class Note {
@ColumnInfo(name = "body")
private String body;
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}

正文字符串的长度,可以是 0 到非常大的数字。

在某些情况下,我们需要

  1. 将所有笔记加载到内存中。
  2. 一个LiveData,它能够通知观察者,如果 SQLitenote表中有任何更改。
  3. 我们只需要body的前 256 个字符。我们不需要整个body.加载所有笔记的整个body字符串可能会导致OutOfMemoryException

我们有以下房间数据库道

@Dao
public abstract class NoteDao {
@Query("SELECT * FROM note")
public abstract LiveData<List<Note>> getAllNotes();
}

getAllNotes能够满足要求(1(和(2(,但不能满足要求(3(。


以下getAllNotesWithShortBody是失败的解决方案。

@Dao
public abstract class NoteDao {
@Query("SELECT * FROM note")
public abstract LiveData<List<Note>> getAllNotes();
@Query("SELECT * FROM note")
public abstract List<Note> getAllNotesSync();
public LiveData<List<Note>> getAllNotesWithShortBody() {
MutableLiveData<List<Note>> notesLiveData = new MutableLiveData<>();
//
// Problem 1: Still can cause OutOfMemoryException by loading 
// List of notes with complete body string.
//
List<Note> notes = getAllNotesSync();
for (Note note : notes) {
String body = note.getBody();
// Extract first 256 characters from body string.
body = body.substring(0, Math.min(body.length(), 256));
note.setBody(body);
}
notesLiveData.postValue(notes);
//
// Problem 2: The returned LiveData unable to inform observers, 
// if there's any changes made in the SQLite `note` table.
//
return notesLiveData;
}
}

我想知道,有没有办法告诉房间数据库 Dao:在将笔记列表作为LiveData返回之前,请通过将字符串修剪为最多 256 个字符来对每个笔记的正文列执行转换?


检查室道生成的源代码

如果我们看一下Room Dao生成的源代码

@Override
public LiveData<List<Note>> getAllNotes() {
final String _sql = "SELECT * FROM note";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
...
...
final String _tmpBody;
_tmpBody = _cursor.getString(_cursorIndexOfBody);
_tmpPlainNote.setBody(_tmpBody);

如果有一种方法可以在运行时提供转换函数,那就太好了,这样我们就可以拥有

final String _tmpBody;
_tmpBody = transform_function(_cursor.getString(_cursorIndexOfBody));
_tmpPlainNote.setBody(_tmpBody);

p/s 请不要反推荐分页库,因为我们的某些功能需要内存中的整个笔记列表(带有修剪的正文字符串(。


您可以使用 SUBSTR,它是 SQLite 的内置函数之一。

@Entity中需要一个主键。假设你称之为id,你可以写一个像下面这样的 SQL。

@Query("SELECT id, SUBSTR(body, 0, 257) AS body FROM note")
public abstract LiveData<List<Note>> getAllNotes();

这会将修剪后的body恢复为 256 个字符。

话虽如此,您应该考虑对行进行分段。如果你有太多行,它们最终会在某个时候耗尽你的内存。使用分页是实现此目的的一种方法。您还可以使用 LIMIT 和 OFFSET 手动浏览行段。

相关内容

最新更新