目前,我们有以下数据库表
@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 到非常大的数字。
在某些情况下,我们需要
- 将所有笔记加载到内存中。
- 一个
LiveData
,它能够通知观察者,如果 SQLitenote
表中有任何更改。 - 我们只需要
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 手动浏览行段。