android - 是否可以在选定的 Room Database 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 到一个非常大的数字。
在某些情况下,我们需要
- 将所有笔记加载到内存中。
- 如果SQLite表
LiveData
中有任何更改,它能够通知观察者。note
- 我们只需要
body
. 我们不需要整个body
. 为所有音符加载整个body
字符串可能会导致.OutOfMemoryException
我们有以下 Room Database Dao
@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;
}
}
我想知道,有什么方法可以告诉 Room 数据库 Dao:在返回 List of Notes as 之前LiveData
,请对每个 Note 的 body 列进行转换,将字符串修剪为最多 256 个字符?
查看 Room Dao 生成的源代码
如果我们看一下 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 目前请不要反推荐 Paging 库,因为我们的某些功能需要内存中的整个笔记列表(带有修剪的正文字符串)。
解决方案
您可以使用 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 手动遍历行段。
推荐阅读
- javascript - 访问另一个堆栈导航器时反应导航不起作用
- python - 在相平面中绘制 ode 解
- c++ - 迭代并写入宏变量?
- python - 使 distutils 将编译后的扩展放在正确的文件夹中
- javascript - 在嵌套函数中包含代码(大约 30 行)更快还是在没有嵌套函数的情况下调用代码更快
- knex.js - User.findOne 不是 knexjs (postgresql) 的函数
- commit - gitbash 提交更改的问题
- javascript - 带有关键字的 Google 搜索和网址
- python - Python:响应浏览器然后继续删除文件
- .net - EF Core 一对多关系:ICollection 还是 Hashset?