Pergunta

Estou consultando o CallLog provedor de conteúdo e a necessidade de detectar os tipos de coluna.

Em Favo de mel e o mais recente (API Level 11+) você pode obter um colunas preferido tipo de dados chamando o método Cursor.getType(int columnIndex) que devolve um dos seguintes tipos:

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

Como posso fazer isso no pré-Favo de mel <11 dispositivos?

Eu já tentei o seguinte:

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

}

No entanto, nenhuma exceção é lançada.Os dados são sempre colocou em primeiro tipo são verificando, neste caso, getInt().Isso significa que, recebo os valores corretos se o tipo de coluna é Inteiro mas um 0 para todos os outros tipos.

Porque não estou procurando na documentação para verificar que tipo é armazenado?As colunas diferentes, dependendo do fabricante do dispositivo e nem todos eles são documentados, consulte a esta pergunta: Como lidar com a fabricante dependente de diferenças em ContentProviders?

Qualquer idéias?

Foi útil?

Solução

Você pode usar esse código quando o cursor estiver posicionado em uma linha válida:

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 que o Cursor.FIELD_TYPE_* valores constantes são definidas de partida de FAVO de mel.

Outras dicas

A expansão Juan resposta, aqui é o meu produto de substituição para a API 11 método de Cursor.getType(int i) - para um cursor reajustado por uma consulta 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;
    }
}

essência: https://gist.github.com/kassim/c340cbfc5243db3a4826

Há algo que pode funcionar :http://developer.android.com/reference/android/database/DatabaseUtils.html cursorRowToContentValues

irá copiar a linha em um ContentValues objeto.Em seguida, você pode chamar ContentValues.get(), que dar-lhe um objeto.em seguida, você pode olhar para a Classe do objeto.

editar

De acordo com o código-fonte de DatabaseUtils, o objeto são bolhas ou Cadeias de caracteres.

edit 2

No entanto, se o seu cursor é uma WindowedCursor, ele tem métodos para saber os tipos de objeto.(isBlob, isString, isLong...)

Eu enfrentei o mesmo problema no passado.Eu abordado com uma muito boa solução.Combinar isso com as suas necessidades.No meu caso eu tenho uma quantidade de objetos diferentes que são todos sincronizados com um servidor na nuvem.Todos eles têm propriedades comuns, de modo que todos eles herdam a partir de um comum BaseObject.Esse objeto possui um método que utiliza um cursor como um parâmetro e retorna um novo objeto do mesmo tipo, de modo que cada objeto que herda-lo, substitui este método com propriedades estendidas de ti.

*Nota que a herança de objetos não é necessário para esta abordagem.É apenas uma maneira mais inteligente de fazê-lo.Contanto que você tenha o mesmo método em todos os objetos que você precisa para tomar forma DB isto irá funcionar como você vai ser capaz de ver na final.

Deixe-me ilustrar:

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

Um novo objeto que herda o primeiro.

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

Finalmente, em seu banco de dados é tão fácil como para solicitar os dados que você deseja chamar um método genérico "getAllObjects" e passando o tipo da classe que você deseja consultar, juntamente com os outros parâmetros da consulta:

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

E lá vai você.Um método genérico para obter qualquer objeto do seu banco de dados e com êxito transformá-lo em um objeto ou uma matriz de objetos em tempo de execução.

Notas:

  • Cada objeto deve ter um método get (), a fim de ser capaz de consultar a tabela para a direita
  • Nesta abordagem, há também um OODB conexão como você pode ver.Você pode usar a mesma abordagem, sem que, por apenas consultar todos os itens (SELECT * FROM...)

Espero que ajude.Resposta de volta, com questões ou dúvidas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top