سؤال

أنا أستفسر عن موفر محتوى CallLog وأحتاج إلى اكتشاف أنواع الأعمدة.

في Honeycomb والأحدث (مستوى 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().وهذا يعني أنني أحصل على القيم الصحيحة إذا كان نوع العمود كذلك عدد صحيح لكن أ 0 لجميع الأنواع الأخرى.

لماذا لا أبحث في الوثائق للتحقق من النوع المخزن؟تختلف الأعمدة حسب الشركة المصنعة للجهاز وليست جميعها موثقة، راجع هذا السؤال: كيفية التعامل مع الاختلافات المعتمدة على الشركة المصنعة في ContentProviders؟

أيه أفكار؟

هل كانت مفيدة؟

المحلول

يمكنك استخدام هذا الرمز عندما يتم وضع المؤشر في صف صالح:

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.

نصائح أخرى

للتوسع في إجابة جوان، هذا هو البديل الخاص بي لطريقة 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

هناك شيء قد ينجح:http://developer.android.com/reference/android/database/DatabaseUtils.html cursorRowToContentValues

سيتم نسخ الصف في كائن ContentValues.بعد ذلك، يمكنك استدعاء ContentValues.get()، الذي يمنحك كائنًا.يمكنك بعد ذلك إلقاء نظرة على فئة هذا الكائن.

يحرر

وفقًا للكود المصدر لـ DatabaseUtils، يكون الكائن إما النقط أو السلاسل.

تحرير 2

ومع ذلك، إذا كان المؤشر الخاص بك هو WindowedCursor، فهو يحتوي على طرق لمعرفة أنواع الكائنات.(isBlob، isString، isLong ...)

لقد واجهت نفس المشكلة في الماضي.لقد تعاملت مع حل جميل جدا.قم بمطابقة هذا مع احتياجاتك.في حالتي لدي عدد من الكائنات المختلفة التي تتم مزامنتها جميعًا مع خادم في السحابة.لديهم جميعًا خصائص مشتركة، بحيث يرثون جميعًا من 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...)

نأمل أن يساعد.الرد مرة أخرى مع القضايا أو الشكوك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top