- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
4 query
现在重点分析一下 SQLiteDatabase 的查询操作:从源码可以看出查询操作最终会调用 rawQueryWithFactory():
public Cursor rawQueryWithFactory( CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable, CancellationSignal cancellationSignal) { acquireReference(); try { SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable, cancellationSignal); return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory, selectionArgs); } finally { releaseReference(); } }
可以看出先构造出 SQLiteDirectCursorDriver,再调用其 query 操作:
// SQLiteDirectCursorDriver::query(): public Cursor query(CursorFactory factory, String[] selectionArgs) { final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal); final Cursor cursor; try { query.bindAllArgsAsStrings(selectionArgs); if (factory == null) { cursor = new SQLiteCursor(this, mEditTable, query); } else { cursor = factory.newCursor(mDatabase, this, mEditTable, query); } } catch (RuntimeException ex) { query.close(); throw ex; } mQuery = query; return cursor; }
流程图:
可以看出先构造出 SQLiteQuery,在构造出 SQLiteCursor,并返回 SQLiteCursor 对象。
所以得到的 Cursor 的原型是 SQLiteCursor 类,你会发现没有其他操作,那么查询数据是在哪里呢?
SQLiteCursor 分析:
public final boolean moveToFirst() { return moveToPosition(0); } public final boolean moveToPosition(int position) { // Make sure position isn't past the end of the cursor final int count = getCount(); if (position >= count) { mPos = count; return false; } // Make sure position isn't before the beginning of the cursor if (position < 0) { mPos = -1; return false; } // Check for no-op moves, and skip the rest of the work for them if (position == mPos) { return true; } boolean result = onMove(mPos, position); if (result == false) { mPos = -1; } else { mPos = position; } return result; } public int getCount() { if (mCount == NO_COUNT) { fillWindow(0); } return mCount; } private void fillWindow(int requiredPos) { clearOrCreateWindow(getDatabase().getPath()); try { if (mCount == NO_COUNT) { int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos, 0); mCount = mQuery.fillWindow(mWindow, startPos, requiredPos, true); mCursorWindowCapacity = mWindow.getNumRows(); if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "received count(*) from native_fill_window: " + mCount); } } else { int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos, mCursorWindowCapacity); mQuery.fillWindow(mWindow, startPos, requiredPos, false); } } catch (RuntimeException ex) { // Close the cursor window if the query failed and therefore will // not produce any results. This helps to avoid accidentally leaking // the cursor window if the client does not correctly handle exceptions // and fails to close the cursor. closeWindow(); throw ex; } } protected void clearOrCreateWindow(String name) { if (mWindow == null) { mWindow = new CursorWindow(name); } else { mWindow.clear(); } }
到这里你会发现 CursorWindow,那这个对象是干嘛的呢?从文档上看可以发现其保存查询数据库的缓存,那么数据是缓存在哪的呢?先看器构造器:
public CursorWindow(String name) { // ... mWindowPtr = nativeCreate(mName, sCursorWindowSize); // .. }
nativeCreate 通过 JNI 调用 CursorWindow.cpp 的 create():
status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) { String8 ashmemName("CursorWindow: "); ashmemName.append(name); status_t result; // 创建共享内存 int ashmemFd = ashmem_create_region(ashmemName.string(), size); if (ashmemFd < 0) { result = -errno; } else { result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE); if (result >= 0) { // 内存映射 void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0); // ... } *outCursorWindow = NULL; return result; }
可以看到查询数据是通过创建共享内存来保存的,但是数据在哪里被保存了呢?继续分析上面 SQLiteCursor:: fillWindow() 函数:
mQuery.fillWindow(mWindow, startPos, requiredPos, true);
其最终会调用 SQLiteConnection::executeForCursorWindow,也是通过 JNI 调用 cpp 文件将查询数据保存到共享内存中。
至于共享内存的知识点,可以参考 Android 系统匿名共享内存 Ashmem
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论