Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8385209
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 9, 20262026-06-09T17:36:41+00:00 2026-06-09T17:36:41+00:00

I have this Cursor implementation (API 10): package com.blablabla.android.helpers.db.cursor; import android.content.ContentResolver; import android.database.AbstractWindowedCursor; import

  • 0

I have this Cursor implementation (API 10):

package com.blablabla.android.helpers.db.cursor;

import android.content.ContentResolver;
import android.database.AbstractWindowedCursor;
import android.database.CharArrayBuffer;
import android.database.ContentObserver;
import android.database.CrossProcessCursor;
import android.database.CursorWindow;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

import com.blablabla.android.helpers.classloader.ClassLoaderHelper;
import com.blablabla.android.helpers.util.BijectiveHashMap;
import com.blablabla.android.helpers.util.BijectiveMap;

/**
 * Cursor for IPC. Takes a CursorWindow as data buffer and the number of columns
 * that CursorWindow has.
 * 
 * @author me@blablabla.eu
 * 
 */
public class ParcelableCursor implements Parcelable, CrossProcessCursor {

    /** Cursor data window */
    protected CursorWindow window = CursorHelper.getCursorWindowInstance();

    /** How many columns we have */
    protected int numColumns = 0;

    /** Column names */
    protected BijectiveMap<String, Integer> colNames = new BijectiveHashMap<String, Integer>();

    /** Current row */
    protected int curRow = -1;

    /** Is this cursor closed? */
    protected boolean closed = false;

    public ParcelableCursor() {
    }

    // /////////////////
    // PARCELABLE IMPLEMENTATION
    // /////////////////

    /** CREATOR for Parcelable */
    public static final Parcelable.Creator<ParcelableCursor> CREATOR = new Parcelable.Creator<ParcelableCursor>() {
        public ParcelableCursor createFromParcel(Parcel in) {
            return new ParcelableCursor(in);
        }

        public ParcelableCursor[] newArray(int size) {
            return new ParcelableCursor[size];
        }
    };

    /** Constructor for Parcelable */
    public ParcelableCursor(Parcel in) {
        readFromParcel(in);
    }

    @Override
    public int describeContents() {
        // Nothing to do here
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeParcelable(window, 0);
        out.writeInt(numColumns);
        out.writeParcelable((Parcelable) colNames, 0);
        out.writeInt(curRow);
        out.writeByte(closed ? (byte) 1 : 0);
    }

    /** Restoring this object from a Parcel */
    public void readFromParcel(Parcel in) {
        window = in.readParcelable(CursorWindow.class.getClassLoader());
        numColumns = in.readInt();
        colNames = in.readParcelable(ClassLoaderHelper.getClassLoader());
        curRow = in.readInt();
        closed = (in.readByte() == 1);
    }

    // ////////////////
    // END PARCELABLE IMPLEMENTATION
    // ////////////////

    // /////////////////
    // CROSS PROCESS CURSOR IMPLEMENTATION
    // /////////////////
    @Override
    public void close() {
        window.close();
        closed = true;
    }

    @Override
    public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
        // TODO: what does this do?
    }

    @Override
    public void deactivate() {
        // Deprecated, does nothing
    }

    @Override
    public byte[] getBlob(int columnIndex) {
        return window.getBlob(curRow, columnIndex);
    }

    @Override
    public int getColumnCount() {
        return numColumns;
    }

    @Override
    public int getColumnIndex(String columnName) {
        int ret = -1;
        Integer col = colNames.get(columnName);
        if (col != null) {
            ret = col;
        }
        return ret;
    }

    @Override
    public int getColumnIndexOrThrow(String columnName)
            throws IllegalArgumentException {
        Integer col = colNames.get(columnName);
        if (col == null) {
            throw new IllegalArgumentException();
        }
        return col;
    }

    @Override
    public String getColumnName(int columnIndex) {
        return colNames.getKey(columnIndex);
    }

    @Override
    public String[] getColumnNames() {
        Log.d("PARCELCURSOR.getColumnNames()", "===GETTING COLNAMES===");
        return colNames.keySet().toArray(new String[colNames.keySet().size()]);
    }

    @Override
    public int getCount() {
        return window.getNumRows();
    }

    @Override
    public double getDouble(int columnIndex) {
        return window.getDouble(curRow, columnIndex);
    }

    @Override
    public Bundle getExtras() {
        // TODO
        return null;
    }

    @Override
    public float getFloat(int columnIndex) {
        return window.getFloat(curRow, columnIndex);
    }

    @Override
    public int getInt(int columnIndex) {
        return window.getInt(curRow, columnIndex);
    }

    @Override
    public long getLong(int columnIndex) {
        return window.getLong(curRow, columnIndex);
    }

    @Override
    public int getPosition() {
        return curRow;
    }

    @Override
    public short getShort(int columnIndex) {
        return window.getShort(curRow, columnIndex);
    }

    @Override
    public String getString(int columnIndex) {
        return window.getString(curRow, columnIndex);
    }

    @Override
    public boolean getWantsAllOnMoveCalls() {
        return false;
    }

    @Override
    public boolean isAfterLast() {
        return (curRow >= window.getNumRows());
    }

    @Override
    public boolean isBeforeFirst() {
        return (curRow < 0);
    }

    @Override
    public boolean isClosed() {
        return closed;
    }

    @Override
    public boolean isFirst() {
        return (curRow == 0);
    }

    @Override
    public boolean isLast() {
        return (curRow == window.getNumRows() - 1);
    }

    @Override
    public boolean isNull(int columnIndex) {
        return window.isNull(curRow, columnIndex);
    }

    @Override
    public boolean move(int offset) {
        int oldPos = curRow;
        curRow += offset;
        if (curRow < -1) {
            curRow = -1;
            return false;
        } else if (curRow > window.getNumRows() - 1) {
            curRow = window.getNumRows() - 1;
            return false;
        }
        return onMove(oldPos, curRow);
    }

    @Override
    public boolean moveToFirst() {
        if (window.getNumRows() == 0) {
            return false;
        }
        int oldPos = curRow;
        curRow = 0;
        return onMove(oldPos, curRow);
    }

    @Override
    public boolean moveToLast() {
        if (window.getNumRows() == 0) {
            return false;
        }
        int oldPos = curRow;
        curRow = window.getNumRows() - 1;
        return onMove(oldPos, curRow);
    }

    @Override
    public boolean moveToNext() {
        int oldPos = curRow++;
        if (isAfterLast()) {
            curRow = window.getNumRows();
            return false;
        }
        return onMove(oldPos, curRow);
    }

    @Override
    public boolean moveToPosition(int position) {
        if (position < -1 && position >= window.getNumRows()) {
            return false;
        }
        int oldPos = curRow;
        curRow = position;
        return onMove(oldPos, curRow);
    }

    @Override
    public boolean moveToPrevious() {
        int oldPos = curRow--;
        if (isBeforeFirst()) {
            curRow = -1;
            return false;
        }
        return onMove(oldPos, curRow);
    }

    /** Not supported */
    @Override
    public void registerContentObserver(ContentObserver observer) {
        // Does nothing
    }

    /** Not supported */
    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        // Does nothing
    }

    /** Deprecated, not supported */
    @Override
    public boolean requery() {
        return false;
    }

    /** Not supported */
    @Override
    public Bundle respond(Bundle extras) {
        // Does nothing
        return null;
    }

    /** Not supported */
    @Override
    public void setNotificationUri(ContentResolver cr, Uri uri) {
        // Does nothing
    }

    /** Not supported */
    @Override
    public void unregisterContentObserver(ContentObserver observer) {
        // Does nothing
    }

    /** Not supported */
    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        // Does nothing
    }

    @Override
    public void fillWindow(int position, CursorWindow window) {
        CursorHelper.copyCursorWindow(position, this.window, window);
    }

    @Override
    public CursorWindow getWindow() {
        CursorWindow ret = new CursorWindow(false);
        fillWindow(0, ret);
        return ret;
    }

    @Override
    public boolean onMove(int oldPosition, int newPosition) {
        // Don't forget to set curRow = -1 if this method returns false
        return true;
    }

    // /////////////////
    // END CROSS PROCESS CURSOR IMPLEMENTATION
    // /////////////////

    /** Sets this cursor using a CursorWindow data */
    public void setFromWindow(CursorWindow window) {
        CursorHelper.copyCursorWindow(0, window, this.window);
        numColumns = CursorHelper.getCursorWindowNumCols(window);
        moveToPosition(-1);
    }

    /** Sets this cursor from another windowed Cursor */
    public void setFromCursor(AbstractWindowedCursor cursor) {

        // Set column names
        String[] colNames = cursor.getColumnNames();
        for (String col : colNames) {
            addColumn(col);
        }

        // Fill window
        window.setNumColumns(numColumns);
        cursor.fillWindow(0, window);
        moveToPosition(-1);
    }

    /**
     * Adds a new column at the end and assigns it this name. This will make
     * this cursor to lose all its data, so you have to add all the columns
     * before adding any row.
     */
    private void addColumn(String name) {
        numColumns++;
        curRow = -1;
        colNames.put(name, numColumns - 1);
    }
}

I send an instance of this Cursor through both Messenger (inside a Message instance) and through ContentProvider.query() (and friends). The problem is that isNull() method works correctly when the Cursor is sent through Messenger but always returns false when sent through the ContentProvider.

This is my ContentProvider.query() implementation:

@Override
public Cursor query(final Uri uri, final String[] projection,
    final String selection, final String[] selectionArgs,
    final String sortOrder) {

    // Build custom query object
    final Query query = getBasicQuery(uri);
    // .... More code preparing the query object

    // Execute the query
    dbManager.executeQuery(getSourceId(uri), query);

    // This is a ParcelableCursor instance
    final Cursor resultCursor = query.getResultCursor();
    return resultCursor;
}

Here, when I am running at the ContentProvider process, the isNull() method works properly, but when the Cursor is received at the client process, it always returns false.

And this is the exception thrown when I do a Cursor.getString() because Cursor.isNull() returns (wrongly) false:

08-13 13:17:16.480: D/SELECT on ui(1572): java.lang.IllegalStateException: UNKNOWN type 0
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.CursorWindow.getString_native(Native Method)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.CursorWindow.getString(CursorWindow.java:329)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:49)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.database.CursorWrapper.getString(CursorWrapper.java:135)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.blablabla.android.core.test.TestDBActivity.selectDB(TestDBActivity.java:332)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.blablabla.android.core.test.TestDBActivity$3.onClick(TestDBActivity.java:169)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.view.View.performClick(View.java:2485)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.view.View$PerformClick.run(View.java:9080)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.os.Handler.handleCallback(Handler.java:587)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.os.Handler.dispatchMessage(Handler.java:92)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.os.Looper.loop(Looper.java:123)
08-13 13:17:16.480: D/SELECT on ui(1572):         at android.app.ActivityThread.main(ActivityThread.java:3683)
08-13 13:17:16.480: D/SELECT on ui(1572):         at java.lang.reflect.Method.invokeNative(Native Method)
08-13 13:17:16.480: D/SELECT on ui(1572):         at java.lang.reflect.Method.invoke(Method.java:507)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-13 13:17:16.480: D/SELECT on ui(1572):         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-13 13:17:16.480: D/SELECT on ui(1572):         at dalvik.system.NativeStart.main(Native Method)

EDIT: after heavy debugging, I can see that when the value is null, isBlob() returns true.

Any ideas of what might be going wrong here?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-09T17:36:42+00:00Added an answer on June 9, 2026 at 5:36 pm

    The problem was actually in CursorHelper.copyCursorWindow(), which is called through fillWindow(), which Android system calls within CursorWrapper. Here’s the buggy version I had of this method:

    /**
     * Copies one CursorWindow into another. Previous data in destination
     * CursorWindow is lost
     * 
     * @param position
     *            Starting position to copy from the origin window
     * @param numColumns
     *            Number of columns in the origin window
     * @param origin
     *            CursorWindow to copy from
     * @param destination
     *            CursorWindow to copy to
     */
    public static void copyCursorWindow(int position, CursorWindow origin,
            CursorWindow destination) {
    
        // Column number
        int numCols = getCursorWindowNumCols(origin);
    
        // Clear destination
        destination.clear();
        destination.setNumColumns(numCols);
    
        // Rows
        int i = position;
        while (i < origin.getNumRows() && destination.allocRow()) {
    
            // Columns
            for (int j = 0; j < numCols; j++) {
    
                if (origin.isBlob(i, j)) {
                    byte[] cur = origin.getBlob(i, j);
                    destination.putBlob(cur, i, j);
    
                } else if (origin.isFloat(i, j)) {
                    Float cur = origin.getFloat(i, j);
                    destination.putDouble(cur, i, j);
    
                } else if (origin.isLong(i, j)) {
                    Long cur = origin.getLong(i, j);
                    destination.putLong(cur, i, j);
    
                } else if (origin.isString(i, j)) {
                    String cur = origin.getString(i, j);
                    destination.putString(cur, i, j);
    
                } else if (origin.isNull(i, j)) {
                    destination.putNull(i, j);
                }
            }
            i++;
        }
    }
    

    The problem here is that isBlob() will return true when the value is actually null. So isNull() should be the first check. Here’s an implementation that works:

    /**
     * Copies one CursorWindow into another. Previous data in destination
     * CursorWindow is lost
     * 
     * @param position
     *            Starting position to copy from the origin window
     * @param numColumns
     *            Number of columns in the origin window
     * @param origin
     *            CursorWindow to copy from
     * @param destination
     *            CursorWindow to copy to
     */
    public static void copyCursorWindow(int position, CursorWindow origin,
            CursorWindow destination) {
    
        // Column number
        int numCols = getCursorWindowNumCols(origin);
    
        // Clear destination
        destination.clear();
        destination.setNumColumns(numCols);
    
        // Rows
        int i = position;
        while (i < origin.getNumRows() && destination.allocRow()) {
    
            // Columns
            for (int j = 0; j < numCols; j++) {
    
                if (origin.isNull(i, j)) {
                    destination.putNull(i, j);
    
                } else if (origin.isFloat(i, j)) {
                    Float cur = origin.getFloat(i, j);
                    destination.putDouble(cur, i, j);
    
                } else if (origin.isLong(i, j)) {
                    Long cur = origin.getLong(i, j);
                    destination.putLong(cur, i, j);
    
                } else if (origin.isString(i, j)) {
                    String cur = origin.getString(i, j);
                    destination.putString(cur, i, j);
    
                } else if (origin.isBlob(i, j)) {
                    byte[] cur = origin.getBlob(i, j);
                    destination.putBlob(cur, i, j);
                }
            }
            i++;
        }
    }
    

    IMHO this is a (annoying) bug in how isBlob() is implemented (although probably fixed in API 11+, because there were some changes in this part -like Cursor.getType() method-).

    (Implementation for getCursorWindowNumCols())

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have this line: @users = database['users'].find(:all).limit(10) it returns this object: <Mongo::Cursor:0x8759a858 namespace='app-development.users' @selector=:all
This is a simple implementation of the ViewHolder pattern. I have a cursor containing
i have this youtube url http://www.youtube.com/watch?v=9N51Etoikfw&feature=youtube_gdata i need to remove the feature parameter and
I have a content provider that is custom to my set of Android applications,
I have this code: cursor = conn.cursor() cursor.execute((insert into new_files (videos_id, filename, is_processing) values
I have this code: cursor.execute( ''' SELECT id,DISTINCT tag FROM userurltag ''') tags =
I'm using an sqlite database in my app. I have this dbhelper class in
I have this code to get the Cursor once for this instance, and the
I have this code in a slot function. QCursor cur=this->cursor(); QMenu* pRightKeyMenu=new QMenu(this); pRightKeyMenu->popup(cur.pos());
I have this error with an sqlite-related cursor. i subclass SQLiteOpenHelper to get access

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.