Cursor.getType() for API Level <11

爱⌒轻易说出口 提交于 2019-11-28 09:41:12

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.

Expanding on Juan's answer, here is my replacement for the API 11 method Cursor.getType(int i) - for a cursor retuned by an SQL query

public class DbCompat {

    protected static final int FIELD_TYPE_BLOB = 4;
    protected static final int FIELD_TYPE_FLOAT = 2;
    protected static final int FIELD_TYPE_INTEGER = 1;
    protected static final int FIELD_TYPE_NULL = 0;
    protected static final int FIELD_TYPE_STRING = 3;

    static int getType(Cursor cursor, int i) throws Exception {
        SQLiteCursor sqLiteCursor = (SQLiteCursor) cursor;
        CursorWindow cursorWindow = sqLiteCursor.getWindow();
        int pos = cursor.getPosition();
        int type = -1;
        if (cursorWindow.isNull(pos, i)) {
            type = FIELD_TYPE_NULL;
        } else if (cursorWindow.isLong(pos, i)) {
            type = FIELD_TYPE_INTEGER;
        } else if (cursorWindow.isFloat(pos, i)) {
            type = FIELD_TYPE_FLOAT;
        } else if (cursorWindow.isString(pos, i)) {
            type = FIELD_TYPE_STRING;
        } else if (cursorWindow.isBlob(pos, i)) {
            type = FIELD_TYPE_BLOB;
        }

        return type;
    }
}

gist: https://gist.github.com/kassim/c340cbfc5243db3a4826

There is something that may work : http://developer.android.com/reference/android/database/DatabaseUtils.html cursorRowToContentValues

will copy the row in a ContentValues object. Then, you can call ContentValues.get(), which give you an object. you can then look at the Class of this object.

edit

According to the source code of DatabaseUtils, the object are either blobs or Strings.

edit 2

However, if your cursor is a WindowedCursor, it has methods to know the object types. (isBlob, isString, isLong...)

I faced the same problem in the past. I tackled it with a pretty nice solution. Match this with your needs. In my case I have an amount of different objects which are all synced to a server in the cloud. They all have common properties, so that they all inherit from a common BaseObject. This object has a method that takes a cursor as a parameter and returns a new object of the same type, so that each object that inherits from it, overrides this method with the extended properties of it.

*Note that the inheritance of objects is not necessary for this approach. It's just a smarter way of doing it. As long as you have the same method in all the objects you need to take form DB this will work as you'll be able to see in the end.

Let me illustrate that:

Our baseObject.

public class BaseObject{

    protected int number;
    protected String text;

    public <T extends BaseObject> T setObject(Cursor c) {
        number = c.getInt(cur.getColumnIndexOrThrow(COLUMN_NAME_FOR_NUMBER));
        text = c.getString(cur.getColumnIndexOrThrow(COLUMN_NAME_FOR_TEXT));

        return (T) this;
    }
}

A new object that inherits from the first.

public class Contact extends BaseObject{

    private String name;

    @Override
    public <T extends BaseObject> T setObject(Cursor c) {

        super.setObject(c);

        name = c.getString(cur.getColumnIndexOrThrow(COLUMN_NAME_FOR_NAME));

        return (T) this;
    }
}

Finally in your database it's as easy as to ask for the data you want by calling a generic method "getAllObjects" and passing the class type you want to query along with the other parameters of the query:

public synchronized <T extends BaseObject> ArrayList<T> getObjectsForClass(final Class<T> classType,
        String selection, String[] selectionArgs, String sort, String limit) {

    ArrayList<T> objects = null;

    if (db == null || !db.isOpen()) {
        db = getWritableDatabase();
    }

    objects = new ArrayList<T>();

    Cursor c = null;
    T object;
    try {
        object = classType.newInstance();

        String table = object.getTable();

        StringBuilder tableSb = new StringBuilder();
        tableSb.append(table).append(" INNER JOIN ").append(Constants.DB_BASE_OBJECT_TABLE)
                .append(" ON ").append(table).append(".").append(BaseObject.DB_OBJECT_ID_KEY).append(" = ")
                .append(Constants.DB_BASE_OBJECT_TABLE).append(".")
                .append(BaseObject.DB_ID_KEY);

        c = db.query(tableSb.toString(), null, selection, selectionArgs, null, null, sort, limit);

        if (c.getCount() > 0) {
            c.moveToFirst();
            while (!c.isAfterLast()) {

                object = classType.newInstance();
                object.setObject(c);
                objects.add(object);

                c.moveToNext();
            }
        }

    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    c.close();

    return objects;
}

And there you go. One generic method to get any object from the your database and to successfully turn it into an object or an array of objects in runtime.

Notes:

  • Every object should have a method getTable() in order to be able to query the right table
  • In this approach there's also a OODB connection as you may see. You can use the same approach without that, by just querying all items (SELECT * FROM...)

Hope it helps. Answer back with issues or doubts.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!