|
Android example source code file (SQLiteCursor.java)
The SQLiteCursor.java Android example source code/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.database.sqlite; import android.database.AbstractWindowedCursor; import android.database.CursorWindow; import android.database.DataSetObserver; import android.database.SQLException; import android.os.Handler; import android.os.Message; import android.os.Process; import android.text.TextUtils; import android.util.Config; import android.util.Log; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.locks.ReentrantLock; /** * A Cursor implementation that exposes results from a query on a * {@link SQLiteDatabase}. * * SQLiteCursor is not internally synchronized so code using a SQLiteCursor from multiple * threads should perform its own synchronization when using the SQLiteCursor. */ public class SQLiteCursor extends AbstractWindowedCursor { static final String TAG = "Cursor"; static final int NO_COUNT = -1; /** The name of the table to edit */ private String mEditTable; /** The names of the columns in the rows */ private String[] mColumns; /** The query object for the cursor */ private SQLiteQuery mQuery; /** The database the cursor was created from */ private SQLiteDatabase mDatabase; /** The compiled query this cursor came from */ private SQLiteCursorDriver mDriver; /** The number of rows in the cursor */ private int mCount = NO_COUNT; /** A mapping of column names to column indices, to speed up lookups */ private Map<String, Integer> mColumnNameMap; /** Used to find out where a cursor was allocated in case it never got released. */ private Throwable mStackTrace; /** * mMaxRead is the max items that each cursor window reads * default to a very high value */ private int mMaxRead = Integer.MAX_VALUE; private int mInitialRead = Integer.MAX_VALUE; private int mCursorState = 0; private ReentrantLock mLock = null; private boolean mPendingData = false; /** * support for a cursor variant that doesn't always read all results * initialRead is the initial number of items that cursor window reads * if query contains more than this number of items, a thread will be * created and handle the left over items so that caller can show * results as soon as possible * @param initialRead initial number of items that cursor read * @param maxRead leftover items read at maxRead items per time * @hide */ public void setLoadStyle(int initialRead, int maxRead) { mMaxRead = maxRead; mInitialRead = initialRead; mLock = new ReentrantLock(true); } private void queryThreadLock() { if (mLock != null) { mLock.lock(); } } private void queryThreadUnlock() { if (mLock != null) { mLock.unlock(); } } /** * @hide */ final private class QueryThread implements Runnable { private final int mThreadState; QueryThread(int version) { mThreadState = version; } private void sendMessage() { if (mNotificationHandler != null) { mNotificationHandler.sendEmptyMessage(1); mPendingData = false; } else { mPendingData = true; } } public void run() { // use cached mWindow, to avoid get null mWindow CursorWindow cw = mWindow; Process.setThreadPriority(Process.myTid(), Process.THREAD_PRIORITY_BACKGROUND); // the cursor's state doesn't change while (true) { mLock.lock(); if (mCursorState != mThreadState) { mLock.unlock(); break; } try { int count = mQuery.fillWindow(cw, mMaxRead, mCount); // return -1 means not finished if (count != 0) { if (count == NO_COUNT){ mCount += mMaxRead; sendMessage(); } else { mCount = count; sendMessage(); break; } } else { break; } } catch (Exception e) { // end the tread when the cursor is close break; } finally { mLock.unlock(); } } } } /** * @hide */ protected class MainThreadNotificationHandler extends Handler { public void handleMessage(Message msg) { notifyDataSetChange(); } } /** * @hide */ protected MainThreadNotificationHandler mNotificationHandler; public void registerDataSetObserver(DataSetObserver observer) { super.registerDataSetObserver(observer); if ((Integer.MAX_VALUE != mMaxRead || Integer.MAX_VALUE != mInitialRead) && mNotificationHandler == null) { queryThreadLock(); try { mNotificationHandler = new MainThreadNotificationHandler(); if (mPendingData) { notifyDataSetChange(); mPendingData = false; } } finally { queryThreadUnlock(); } } } /** * Execute a query and provide access to its result set through a Cursor * interface. For a query such as: {@code SELECT name, birth, phone FROM * myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth, * phone) would be in the projection argument and everything from * {@code FROM} onward would be in the params argument. This constructor * has package scope. * * @param db a reference to a Database object that is already constructed * and opened * @param editTable the name of the table used for this query * @param query the rest of the query terms * cursor is finalized */ public SQLiteCursor(SQLiteDatabase db, SQLiteCursorDriver driver, String editTable, SQLiteQuery query) { // The AbstractCursor constructor needs to do some setup. super(); mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace(); mDatabase = db; mDriver = driver; mEditTable = editTable; mColumnNameMap = null; mQuery = query; try { db.lock(); // Setup the list of columns int columnCount = mQuery.columnCountLocked(); mColumns = new String[columnCount]; // Read in all column names for (int i = 0; i < columnCount; i++) { String columnName = mQuery.columnNameLocked(i); mColumns[i] = columnName; if (Config.LOGV) { Log.v("DatabaseWindow", "mColumns[" + i + "] is " + mColumns[i]); } // Make note of the row ID column index for quick access to it if ("_id".equals(columnName)) { mRowIdColumnIndex = i; } } } finally { db.unlock(); } } /** * @return the SQLiteDatabase that this cursor is associated with. */ public SQLiteDatabase getDatabase() { return mDatabase; } @Override public boolean onMove(int oldPosition, int newPosition) { // Make sure the row at newPosition is present in the window if (mWindow == null || newPosition < mWindow.getStartPosition() || newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) { fillWindow(newPosition); } return true; } @Override public int getCount() { if (mCount == NO_COUNT) { fillWindow(0); } return mCount; } private void fillWindow (int startPos) { if (mWindow == null) { // If there isn't a window set already it will only be accessed locally mWindow = new CursorWindow(true /* the window is local only */); } else { mCursorState++; queryThreadLock(); try { mWindow.clear(); } finally { queryThreadUnlock(); } } mWindow.setStartPosition(startPos); mCount = mQuery.fillWindow(mWindow, mInitialRead, 0); // return -1 means not finished if (mCount == NO_COUNT){ mCount = startPos + mInitialRead; Thread t = new Thread(new QueryThread(mCursorState), "query thread"); t.start(); } } @Override public int getColumnIndex(String columnName) { // Create mColumnNameMap on demand if (mColumnNameMap == null) { String[] columns = mColumns; int columnCount = columns.length; HashMap<String, Integer> map = new HashMap Other Android examples (source code examples)Here is a short list of links related to this Android SQLiteCursor.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.