想要了解GreenDao如何進行數據庫CRUD操作,那麼可以看源碼。
查詢:
先看最簡單最容記得查詢方法queryBuilder().list()。
/** Executes the query and returns the result as a list containing all entities loaded into memory. */
public List<T> list() {
checkThread();
Cursor cursor = dao.getDatabase().rawQuery(sql, parameters);
return daoAccess.loadAllAndCloseCursor(cursor);
}
通過sql語句進行查詢,然後返回一個遊標。根據這個遊標進行處理。查看下方法實現
/** Reads all available rows from the given cursor and returns a list of entities. */
protected List<T> loadAllFromCursor(Cursor cursor) {
int count = cursor.getCount();
if (count == 0) {
return new ArrayList<T>();
}
List<T> list = new ArrayList<T>(count);
CursorWindow window = null;
boolean useFastCursor = false;
if (cursor instanceof CrossProcessCursor) {
window = ((CrossProcessCursor) cursor).getWindow();
if (window != null) { // E.g. Robolectric has no Window at this point
if (window.getNumRows() == count) {
cursor = new FastCursor(window);
useFastCursor = true;
} else {
DaoLog.d("Window vs. result size: " + window.getNumRows() + "/" + count);
}
}
}
if (cursor.moveToFirst()) {
if (identityScope != null) {
identityScope.lock();
identityScope.reserveRoom(count);
}
try {
if (!useFastCursor && window != null && identityScope != null) {
loadAllUnlockOnWindowBounds(cursor, window, list);
} else {
do {
list.add(loadCurrent(cursor, 0, false));
} while (cursor.moveToNext());
}
} finally {
if (identityScope != null) {
identityScope.unlock();
}
}
}
return list;
}
看到這裏,發現和我們自己寫SQLite原生查詢的時候處理遊標差不多。
它首先判斷cursor是否爲空,接着新建List,再從遊標中讀取數據存進list中然後返回,整體理解起來不難。那麼它轉化成我們需要的對象是在loadCurrent()這個方法中。
final protected T loadCurrent(Cursor cursor, int offset, boolean lock)
所以總體思路是這樣:
我們調用實體類Dao的queryBuilder().list()方法,接着它使用SQL語句進行數據庫查詢,返回一個cursor,再對cursor進行解析,解析cursor的方法是
final protected T loadCurrent(Cursor cursor, int offset, boolean lock)
,存進List中返回給我們。
再看看queryBuilder().listLazy()
該方法返回一個LazyList<T>,這個LazyList是實現了List接口的,我們得到這個LazyList時,操作相關的數據是的方法有構造方法和get方法。
看下他實現的的方法。構造方法
LazyList(InternalQueryDaoAccess<E> daoAccess, Cursor cursor, boolean cacheEntities) {
this.cursor = cursor;
this.daoAccess = daoAccess;
size = cursor.getCount();
if (cacheEntities) {
entities = new ArrayList<E>(size);
for (int i = 0; i < size; i++) {
entities.add(null);
}
} else {
entities = null;
}
if (size == 0) {
cursor.close();
}
lock = new ReentrantLock();
}
@Override
public E get(int location) {
if (entities != null) {
E entity = entities.get(location);
if (entity == null) {
lock.lock();
try {
entity = entities.get(location);
if (entity == null) {
entity = loadEntity(location);
entities.set(location, entity);
// Ignore FindBugs: increment of volatile is fine here because we use a lock
loadedCount++;
if (loadedCount == size) {
cursor.close();
}
}
} finally {
lock.unlock();
}
}
return entity;
} else {
lock.lock();
try {
return loadEntity(location);
} finally {
lock.unlock();
}
}
}
可以看到LazyList中的get方法是線程安全的,裏面使用了雙重檢驗。提高了多線程的安全性和效率。裏面使用了loadEntity()方法來解析遊標數據,查看源碼
可以發現最終也調用了loadCurrent()方法來解析cursor並封裝成一個實體類返回給get方法。最後封裝成一個LazyList返回給用戶。
總體思路是這樣:
用戶調用queryBuilder().LazyList()方法,該方法使用SQL語句進行數據庫查詢並返回一個遊標,接着遊標層層傳遞,在LazyList的get方法中進行數據解析,解析cursor的方法是loadEntity(location),但是該方法調用了loadCurrent方法,所以最終解析cursor數據的方法是loadCurrent,然後封裝成實體類返回,裝載進LazyList返回給用戶,完成查詢。
再看看迭代查詢,queryBuilder().listIterator()
該方法返回一個迭代器,在迭代器中獲取數據使用到next()方法,判斷是否還有數據則使用hasNext()方法,接下來看看源碼
層層進入源碼,最終 發現進入的是LazyList
看看next()方法,非常容易理解,裏面通過一個get()方法來進行數據的獲取
@Override
public E next() {
if (index >= size) {
throw new NoSuchElementException();
}
E entity = get(index);
index++;
if (index == size && closeWhenDone) {
close();
}
return entity;
}
點進去發現和我們的Lislazy方法一毛一樣!! 也是最終通過loadCurrent()方法解析遊標數據進行實體類封裝返回給用戶。
其實除了list方法,其餘的三個查詢方法都用到了LazyList類,最終調用的步驟也是一致。不過和list的區別就是惰性加載(按需加載),而且需要開發者手動關閉連接。
總體思路:
用戶調用該方法,然後它new 一個迭代器,通過LazyList類的get方法加載數據封裝實體存進迭代器返回給用戶。