24

CallLog コンテンツ プロバイダーにクエリを実行していて、列の種類を検出する必要があります。

Cursor.getType(int columnIndex)Honeycomb 以降 (API レベル 11+) では、次の型のいずれかを返すメソッドを呼び出すことで、列の優先データ型を取得できます。

  • 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()) にキャストされます。つまり、列の型がIntegerの場合は正しい値が得られますが、他のすべての型の場合は0になります。

どのタイプが格納されているかを確認するためにドキュメントを調べないのはなぜですか? 列はデバイスの製造元によって異なり、すべてが文書化されているわけではありません。次の質問を参照してください: ContentProviders の製造元依存の違いを処理する方法は?

何か案は?

4

4 に答える 4

12

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

于 2013-12-19T15:31:04.507 に答える
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 から始まることに注意してください。

于 2013-09-24T00:45:15.483 に答える
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;
}

そして、あなたは行き​​ます。データベースから任意のオブジェクトを取得し、実行時にオブジェクトまたはオブジェクトの配列に正常に変換するための1つの一般的なメソッド。

ノート:

  • 適切なテーブルをクエリできるようにするには、すべてのオブジェクトにgetTable()メソッドが必要です。
  • このアプローチでは、ご覧のとおり、OODB接続もあります。すべてのアイテムにクエリを実行するだけで、それがなくても同じアプローチを使用できます(SELECT * FROM ...)

それが役に立てば幸い。問題や疑問を返してください。

于 2012-08-27T13:02:38.960 に答える
0

動作する可能性のあるものがあります: http://developer.android.com/reference/android/database/DatabaseUtils.html cursorRowToContentValues

行を ContentValues オブジェクトにコピーします。次に、オブジェクトを取得する ContentValues.get() を呼び出すことができます。次に、このオブジェクトのクラスを確認できます。

編集

DatabaseUtils のソース コードによると、オブジェクトは blob または String のいずれかです。

編集 2

ただし、カーソルが WindowedCursor の場合は、オブジェクトの種類を知るためのメソッドがあります。(isBlob、isString、isLong...)

于 2012-08-23T14:34:05.297 に答える