API Level< 11的Cursor.getType()

时间:2012-07-25 20:39:43

标签: android android-contentprovider android-cursor

我正在查询CallLog内容提供程序,需要检测列类型。

在Honeycomb和更新版本(API Level 11+)中,您可以通过调用返回以下类型之一的方法Cursor.getType(int columnIndex)来获取列首选数据类型:

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

如何在Honeycomb< 11设备上实现这一目标?

我尝试了以下内容:

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;
                }
           }
       }
   }

}

但是,不会抛出异常。数据始终以您要检查的第一种类型进行转换,在本例中为getInt()。这意味着,如果列类型为整数,则我得到正确的值,而对于所有其他类型,我得到 0

为什么我不查看文档来检查存储的类型? 这些列因设备制造商而异,并非所有列都有记录,请参阅此问题:How to handle manufacturer-dependent differences in ContentProviders?

有什么想法吗?

4 个答案:

答案 0 :(得分:11)

扩展Juan的答案,这里是我对API 11方法Cursor.getType(int i)的替代 - 对于由SQL查询重新调整的游标

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;
    }
}

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

答案 1 :(得分:10)

当光标位于有效行中时,您可以使用此代码:

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";
    }
}

请注意,Cursor.FIELD_TYPE_ *常量值是从HONEYCOMB开始定义的。

答案 2 :(得分:0)

有些东西可行: http://developer.android.com/reference/android/database/DatabaseUtils.html cursorRowToContentValues

将复制ContentValues对象中的行。然后,您可以调用ContentValues.get(),它会为您提供一个对象。然后,您可以查看此对象的类。

修改

根据DatabaseUtils的源代码,对象是blob或Strings。

编辑2

但是,如果您的光标是WindowedCursor,则它具有了解对象类型的方法。 (isBlob,isString,isLong ...)

答案 3 :(得分:0)

我过去遇到过同样的问题。我用一个非常好的解决方案解决了这个问题。 将其与您的需求相匹配。 在我的情况下,我有一些不同的对象,它们都同步到云中的服务器。它们都具有公共属性,因此它们都从公共BaseObject继承。 此对象有一个方法,它将游标作为参数并返回相同类型的新对象,以便从其继承的每个对象都使用它的扩展属性覆盖此方法。

*请注意,此方法不需要继承对象。这只是一种更聪明的方式。只要您在所有对象中使用相同的方法,您需要使用表格DB,这将最终能够看到。

让我说明一下:

我们的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;
    }
}

从第一个继承的新对象。

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;
    }
}

最后在您的数据库中,通过调用泛型方法“getAllObjects”并将要查询的类类型与查询的其他参数一起传递,就可以轻松地询问所需的数据:

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;
}

你去吧。从数据库中获取任何对象并在运行时成功将其转换为对象或对象数组的一种通用方法。

注意:

  • 每个对象都应该有一个方法getTable(),以便能够查询正确的表
  • 在这种方法中,您可能还会看到OODB连接。只需查询所有项目(SELECT * FROM ...)
  • ,您就可以使用相同的方法

希望它有所帮助。回答问题或怀疑。