APIレベル<11のCURSOR.GETTYPE()
-
11-12-2019 - |
質問
カールログコンテンツプロバイダに照会して、列の種類を検出する必要があります。
HoneyCombおよびNewer(APIレベル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)
ハニカム<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 です。
どのタイプが保存されているかを確認するためにドキュメントを見ていないのですか? 列はデバイスの製造元によって異なり、それらのすべてが文書化されているわけではありません。 ContentSrovidersの製造元に依存の違いを処理する方法は?
解決
カーソルが有効な行に配置されているときにこのコードを使用できます。
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_ *定数値は、ハニカムから始めて定義されます。
他のヒント
Juanの答えの拡大は、API 11メソッドCURSOR.GETTYPE(int i)のための私の置き換えです。
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;
}
}
.
うまくいくかもしれないものがあります。 http://developer.android.com/reference/android/database/databaseutils.html. CurSorrowToContentValues
はContentValuesオブジェクト内の行をコピーします。次に、ContentValues.get()を呼び出すことができます。これにより、オブジェクトがあります。その後、このオブジェクトのクラスを見ることができます。
編集
DatabaseUtilsのソースコードに従って、オブジェクトはBLOBまたは文字列のいずれかです。
編集2
しかし、カーソルがWindowedCursorの場合は、オブジェクト型を知る方法があります。(ISBLOB、ISSTRING、ISLONG ...)
私は過去に同じ問題に直面しました。私はかなり素敵な解決策でそれに取り組みました。 あなたのニーズとこれを一致させます。 私の場合、私はすべてクラウド内のサーバーに同期されているさまざまなオブジェクトの量があります。それらはすべて一般的なプロパティを持っているので、それらはすべて共通の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;
}
}
.
最後にデータベース内にgenericメソッド "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つの一般的な方法。
注:
- すべてのオブジェクトには、正しいテーブルを照会できるようにするためにmethod gettable()が必要です。
- このアプローチでは、あなたが見るかもしれないようにOODB接続もあります。すべてのアイテムを問い合わせるだけで、それなしで同じアプローチを使用することができます(*から*から*)
それが役立つことを願っています。問題や疑問で答えます。