FileDocCategorySizeDatePackage
SortCursor.javaAPI DocAndroid 1.5 API9265Wed May 06 22:41:56 BST 2009com.android.internal.database

SortCursor

public class SortCursor extends android.database.AbstractCursor
A variant of MergeCursor that sorts the cursors being merged. If decent performance is ever obtained, it can be put back under android.database.

Fields Summary
private static final String
TAG
private android.database.Cursor
mCursor
private android.database.Cursor[]
mCursors
private int[]
mSortColumns
private final int
ROWCACHESIZE
private int[]
mRowNumCache
private int[]
mCursorCache
private int[]
mCurRowNumCache
private int
mLastCacheHit
private android.database.DataSetObserver
mObserver
Constructors Summary
public SortCursor(android.database.Cursor[] cursors, String sortcolumn)

    
        
    
        mCursors = cursors;

        int length = mCursors.length;
        mSortColumns = new int[length];
        for (int i = 0 ; i < length ; i++) {
            if (mCursors[i] == null) continue;
            
            // Register ourself as a data set observer
            mCursors[i].registerDataSetObserver(mObserver);
            
            mCursors[i].moveToFirst();

            // We don't catch the exception
            mSortColumns[i] = mCursors[i].getColumnIndexOrThrow(sortcolumn);
        }
        mCursor = null;
        String smallest = "";
        for (int j = 0 ; j < length; j++) {
            if (mCursors[j] == null || mCursors[j].isAfterLast())
                continue;
            String current = mCursors[j].getString(mSortColumns[j]);
            if (mCursor == null || current.compareToIgnoreCase(smallest) < 0) {
                smallest = current;
                mCursor = mCursors[j];
            }
        }

        for (int i = mRowNumCache.length - 1; i >= 0; i--) {
            mRowNumCache[i] = -2;
        }
        mCurRowNumCache = new int[ROWCACHESIZE][length];
    
Methods Summary
public voidclose()

        int length = mCursors.length;
        for (int i = 0 ; i < length ; i++) {
            if (mCursors[i] == null) continue;
            mCursors[i].close();
        }
    
public booleancommitUpdates()

        int length = mCursors.length;
        for (int i = 0 ; i < length ; i++) {
            if (mCursors[i] != null) {
                mCursors[i].commitUpdates();
            }
        }
        onChange(true);
        return true;
    
public voiddeactivate()

        int length = mCursors.length;
        for (int i = 0 ; i < length ; i++) {
            if (mCursors[i] == null) continue;
            mCursors[i].deactivate();
        }
    
public booleandeleteRow()

        return mCursor.deleteRow();
    
public byte[]getBlob(int column)

        return mCursor.getBlob(column);   
    
public java.lang.String[]getColumnNames()

        if (mCursor != null) {
            return mCursor.getColumnNames();
        } else {
            // All of the cursors may be empty, but they can still return
            // this information.
            int length = mCursors.length;
            for (int i = 0 ; i < length ; i++) {
                if (mCursors[i] != null) {
                    return mCursors[i].getColumnNames();
                }
            }
            throw new IllegalStateException("No cursor that can return names");
        }
    
public intgetCount()

        int count = 0;
        int length = mCursors.length;
        for (int i = 0 ; i < length ; i++) {
            if (mCursors[i] != null) {
                count += mCursors[i].getCount();
            }
        }
        return count;
    
public doublegetDouble(int column)

        return mCursor.getDouble(column);
    
public floatgetFloat(int column)

        return mCursor.getFloat(column);
    
public intgetInt(int column)

        return mCursor.getInt(column);
    
public longgetLong(int column)

        return mCursor.getLong(column);
    
public shortgetShort(int column)

        return mCursor.getShort(column);
    
public java.lang.StringgetString(int column)

        return mCursor.getString(column);
    
public booleanisNull(int column)

        return mCursor.isNull(column);
    
public booleanonMove(int oldPosition, int newPosition)

        if (oldPosition == newPosition)
            return true;

        /* Find the right cursor
         * Because the client of this cursor (the listadapter/view) tends
         * to jump around in the cursor somewhat, a simple cache strategy
         * is used to avoid having to search all cursors from the start.
         * TODO: investigate strategies for optimizing random access and
         * reverse-order access.
         */

        int cache_entry = newPosition % ROWCACHESIZE;

        if (mRowNumCache[cache_entry] == newPosition) {
            int which = mCursorCache[cache_entry];
            mCursor = mCursors[which];
            if (mCursor == null) {
                Log.w(TAG, "onMove: cache results in a null cursor.");
                return false;
            }
            mCursor.moveToPosition(mCurRowNumCache[cache_entry][which]);
            mLastCacheHit = cache_entry;
            return true;
        }

        mCursor = null;
        int length = mCursors.length;

        if (mLastCacheHit >= 0) {
            for (int i = 0; i < length; i++) {
                if (mCursors[i] == null) continue;
                mCursors[i].moveToPosition(mCurRowNumCache[mLastCacheHit][i]);
            }
        }

        if (newPosition < oldPosition || oldPosition == -1) {
            for (int i = 0 ; i < length; i++) {
                if (mCursors[i] == null) continue;
                mCursors[i].moveToFirst();
            }
            oldPosition = 0;
        }
        if (oldPosition < 0) {
            oldPosition = 0;
        }

        // search forward to the new position
        int smallestIdx = -1;
        for(int i = oldPosition; i <= newPosition; i++) {
            String smallest = "";
            smallestIdx = -1;
            for (int j = 0 ; j < length; j++) {
                if (mCursors[j] == null || mCursors[j].isAfterLast()) {
                    continue;
                }
                String current = mCursors[j].getString(mSortColumns[j]);
                if (smallestIdx < 0 || current.compareToIgnoreCase(smallest) < 0) {
                    smallest = current;
                    smallestIdx = j;
                }
            }
            if (i == newPosition) break;
            if (mCursors[smallestIdx] != null) {
                mCursors[smallestIdx].moveToNext();
            }
        }
        mCursor = mCursors[smallestIdx];
        mRowNumCache[cache_entry] = newPosition;
        mCursorCache[cache_entry] = smallestIdx;
        for (int i = 0; i < length; i++) {
            if (mCursors[i] != null) {
                mCurRowNumCache[cache_entry][i] = mCursors[i].getPosition();
            }
        }
        mLastCacheHit = -1;
        return true;
    
public voidregisterDataSetObserver(android.database.DataSetObserver observer)

        int length = mCursors.length;
        for (int i = 0 ; i < length ; i++) {
            if (mCursors[i] != null) {
                mCursors[i].registerDataSetObserver(observer);
            }
        }
    
public booleanrequery()

        int length = mCursors.length;
        for (int i = 0 ; i < length ; i++) {
            if (mCursors[i] == null) continue;
            
            if (mCursors[i].requery() == false) {
                return false;
            }
        }

        return true;
    
public voidunregisterDataSetObserver(android.database.DataSetObserver observer)

        int length = mCursors.length;
        for (int i = 0 ; i < length ; i++) {
            if (mCursors[i] != null) {
                mCursors[i].unregisterDataSetObserver(observer);
            }
        }