Search code examples
androidandroid-contentproviderandroid-cursor

Cursor.getType() for API Level <11


I'm querying the CallLog content provider and need to detect the column types.

In Honeycomb and newer (API Level 11+) you can get a columns preferred data type by calling the method Cursor.getType(int columnIndex) which returns one of the following types:

  • FIELD_TYPE_NULL (0)
  • FIELD_TYPE_INTEGER (1)
  • FIELD_TYPE_FLOAT (2)
  • FIELD_TYPE_STRING (3)
  • FIELD_TYPE_BLOB (4)

How can I accomplish this on pre-Honeycomb <11 devices?

I've tried the following:

for ( int i = 0; i < cursor.getColumnCount(); i++ ) {    

    int columnType = -1;
    try {
        cursor.getInt( i );
        columnType = Cursor.FIELD_TYPE_INTEGER;

    } catch ( Exception ignore ) {

        try {
            cursor.getString( i );
            columnType = Cursor.FIELD_TYPE_STRING;

        } catch ( Exception ignore1 ) {

            try {
                cursor.getFloat( i );
                columnType = Cursor.FIELD_TYPE_FLOAT;

            } catch ( Exception ignore2 ) {

                try {                                             
                  cursor.getBlob( i );
                  columnType = Cursor.FIELD_TYPE_BLOB;

                } catch ( Exception ignore3 ) {

                     columnType = Cursor.FIELD_TYPE_NULL;
                }
           }
       }
   }

}

However, no exception is thrown. The data is always casted in the first type you are checking for, in this case getInt(). That means, I get the correct values if the column type is Integer but a 0 for all other types.

Why am I not looking in the documentation to check what type is stored? The columns differ depending on the device manufacturer and not all of them are documented, see this question: How to handle manufacturer-dependent differences in ContentProviders?

Any ideas?


Solution

  • You can use this code when cursor is positioned in a valid row:

    CursorWrapper cw = (CursorWrapper)cursor;
    
    Class<?> cursorWrapper = CursorWrapper.class;
    Field mCursor = cursorWrapper.getDeclaredField("mCursor");
    mCursor.setAccessible(true);
    AbstractWindowedCursor abstractWindowedCursor = (AbstractWindowedCursor)mCursor.get(cw);
    CursorWindow cursorWindow = abstractWindowedCursor.getWindow();
    int pos = abstractWindowedCursor.getPosition();
    for ( int i = 0; i < cursor.getColumnCount(); i++ ) {
        String type = null;
        if (cursorWindow.isNull(pos, i)) {
            type = "Cursor.FIELD_TYPE_NULL";
        } else if (cursorWindow.isLong(pos, i)) {
            type = "Cursor.FIELD_TYPE_INTEGER";
        } else if (cursorWindow.isFloat(pos, i)) {
            type = "Cursor.FIELD_TYPE_FLOAT";
        } else if (cursorWindow.isString(pos, i)) {
            type = "Cursor.FIELD_TYPE_STRING";
        } else if (cursorWindow.isBlob(pos, i)) {
            type = "Cursor.FIELD_TYPE_BLOB";
        }
    }
    

    Note that Cursor.FIELD_TYPE_* constant values are defined starting from HONEYCOMB.