POJO против курсоров в Android

Обычно я склонен определять уровень модели своих приложений с помощью POJO, таких как статья, комментарий и т. д.

Я собирался реализовать AlphabetIndexer в адаптере одного из моих ListView. Прямо сейчас этот адаптер принимает коллекцию статей, которую я обычно получаю из своей оболочки вокруг базы данных SQLiteDatabase.

Сигнатура конструктора AlphabetIndexer выглядит следующим образом:

public AlphabetIndexer (Cursor cursor, int sortedColumnIndex, CharSequence alphabet)

Поскольку это не принимает коллекцию или что-то подобное, а только курсор, это заставило меня задуматься: может быть, мне не следует создавать объекты для моей модели, а просто использовать курсоры, возвращенные из базы данных?

Итак, вопрос, я думаю, таков: что мне делать, представлять данные с помощью коллекций POJO или просто работать с курсорами во всем приложении?

Любой вклад?


person benvd    schedule 30.03.2010    source источник
comment
Хотели бы вы использовать курсоры, предоставляемые библиотекой? См.: stackoverflow.com/questions/4285398/   -  person OneWorld    schedule 26.11.2010
comment
Я делаю что-то подобное ЗДЕСЬ stackoverflow .com/questions/10224233/   -  person toobsco42    schedule 26.04.2012


Ответы (4)


Я столкнулся с подобными проблемами. Сейчас я отхожу от POJO. Обратите внимание, однако, что вы можете создать свой собственный Cursor интерфейс для набора POJO, если вы того пожелаете.

person CommonsWare    schedule 30.03.2010
comment
Я знаю об этом, но это кажется немного круговым... создание курсора для коллекции, созданной из курсора. :) - person benvd; 30.03.2010
comment
О, без вопросов. Это одна из причин, по которой я отказываюсь от POJO и оставляю вещи только в Cursors. В терминах MVC вы получаете глупые модели и умные контроллеры. - person CommonsWare; 30.03.2010
comment
Я решил принять это как ответ, так как я сейчас использую этот подход. В частности, я создал общедоступный внутренний класс в своем SQLiteOpenHelper для каждой таблицы, которая у него есть. Эти классы содержат множество методов, чтобы мне не приходилось возиться с именами столбцов или числами. Разница в производительности сразу бросается в глаза в ListViews всего лишь с несколькими десятками записей. Кроме того, я предпочитаю CursorAdapters BaseAdapters. Я получил вдохновение для этого из ваших книг (в частности, на странице 102 в Android Tutorials 2.9), которых у меня не было, когда я задавал этот вопрос, так что спасибо! :-) - person benvd; 27.07.2010

Мне нравится создавать классы POJO с поддержкой курсора. Класс POJO с поддержкой Cursor имеет конструктор, который принимает Cursor и обеспечивает следующие преимущества:

  • Простые в использовании геттеры, которые возвращают правильный тип контента, намного лучше, чем получение индексов и необходимость запоминать тип данных в базе данных.
  • Методы-получатели, которые вычисляют свои результаты из других методов-получателей, точно так же, как должно быть объектно-ориентированное программирование.
  • Возвращаемые значения геттера могут быть перечислениями!

Эти несколько преимуществ стоят некоторого стандартного кода, многие ошибки были предотвращены теперь, когда инженеры-пользователи сами не обращаются к столбцам курсора. Мы по-прежнему используем класс CursorAdapter, но первой строкой в ​​методе bindView является создание POJO с поддержкой Cursor из Cursor, и с этого момента код становится красивым.

Ниже приведен пример реализации, для инженеров-пользователей несложно превратить непрозрачный курсор в четко определенный объект пользователя, с этого момента его можно передавать и получать к нему доступ, как к обычному POJO, пока поддерживающий курсор не закрыт. SmartUserCursor — это специальный класс, который я написал для обеспечения того, чтобы позиция курсора запоминалась и восстанавливалась до того, как к курсору будет осуществлен доступ, а также он сохраняет индексы столбцов курсора, чтобы поиск выполнялся быстро.

ПРИМЕР:

public class User {

    private final SmartUserCursor mCursor;

    public User(SmartUserCursor cursor, int position) {
        mCursor = new SmartUserCursor(cursor, position);
    }

    public long getUserId() {
        return mCursor.getLong(SmartUserCursor.Columns.userId);
    }

    public UserType getType() {
        return UserType.valueOf(mCursor.getString(SmartUserCursor.Columns.type));
    }

    public String getFirstName() {
        return mCursor.getString(SmartUserCursor.Columns.firstName);
    }

    public String getLastName() {
        return mCursor.getString(SmartUserCursor.Columns.lastName);
    }

    public final String getFullName() {
        return getFirstName() + " " + getLastName();
    }

    public static User newUserFromAdapter(BaseAdapter adapter, int position) {
        return new User((SmartUserCursor)adapter.getItem(position), position);
    }

    public static User newUserBlocking(Context context, long UserId) {
        Cursor cursor = context.getContentResolver().query(
                Users.CONTENT_URI_CLIENT,
                Users.DEFAULT_USER_PROJECTION,
                Users.Columns.USER_ID+"=?",
                new String[] {String.valueOf(UserId)},
                null
        );

        if (cursor == null || !cursor.moveToFirst()) {
            throw new RuntimeException("No User with id " + UserId + " exists");
        }

        return new User(new SmartUserCursor(cursor, Users.DEFAULT_USER_PROJECTION), -1);
    }

    public final void closeBackingCursor() {
        mCursor.close();
    }

}
person satur9nine    schedule 27.06.2012
comment
любой пример кода? Также это медленнее, так как вам нужно загрузить все данные из курсоров в объекты модели? - person marchinram; 06.07.2012
comment
Я не загружаю все данные из курсора. У меня просто есть куча геттеров, которые обращаются к курсору внутри. Позже выложу пример. - person satur9nine; 06.07.2012
comment
круто, спасибо, с нетерпением жду примера, в настоящее время я использую greendao, который, я думаю, делает что-то подобное, но было бы здорово увидеть пример того, как это работает - person marchinram; 07.07.2012
comment
круто, спасибо, например, мы тоже можем увидеть SmartUserCursor или это для клиента? Кроме того, когда вы закроете вспомогательный курсор? - person marchinram; 09.07.2012
comment
Я не могу дать код для SmartUserCursor, но это всего лишь вспомогательный класс, и он не является строго необходимым для этого примера. Инженер-пользователь по-прежнему должен знать, когда закрывать курсор. - person satur9nine; 20.07.2012
comment
Является ли SmartUserCursor расширением Cursor или это просто оболочка, в которой вы повторно реализуете такие функции, как getString()? - person Marian Klühspies; 21.06.2014
comment
SmartUserCursor — это класс, который переопределяет такие функции, как getString, для получения значений перечисления. Основная цель SmartUserCursor состоит в том, чтобы не искать индекс столбца все время, он просматривает его один раз внутри и запоминает. Это оптимизация производительности. - person satur9nine; 22.06.2014

Один голос за объекты сущностей (POJO). Передача курсоров, особенно на слой пользовательского интерфейса, кажется мне такой неправильной (независимо от того, подразумевает ли это Android SDK). Обычно есть несколько способов заполнить ваш пользовательский интерфейс, и я стараюсь избегать тех, которые напрямую используют курсоры. Например, чтобы заполнить свои пользовательские представления списка, я использую SimpleAdapter и даю объектам своей коллекции возможность возвращать представление себя как List<? extends Map<String, ?>> для конструктора SimpleAdapter.

Я использую шаблон, в котором каждая таблица обернута объектом сущности и имеет класс поставщика, который обрабатывает мои операции CRUD, связанные с этой сущностью. При желании, если мне нужны расширенные функциональные возможности для коллекций, я также их оборачиваю (т.е. EntityItems extends ArrayList<EntityItem>). У провайдера есть базовый класс, который я передаю ссылку классу DbAdapter, который выполняет тяжелую работу вокруг базы данных.

Основная причина, помимо личных предпочтений, заключается в том, что я хочу скрыть этот код как можно дальше от своего пользовательского интерфейса:

String something = cursor.getString(cursor.getColumnIndex(COLUMN_NAME_CONSTANT));

Если я вижу такой код, встроенный в слой пользовательского интерфейса, я обычно ожидаю увидеть гораздо худший код, скрывающийся за углом. Может быть, я просто провел слишком много времени в корпоративном мире, работая в больших командах, но я предпочитаю удобочитаемость, если нет серьезной проблемы с производительностью или если это достаточно небольшая задача, где выразительность просто излишняя для предприятия.

person Rich    schedule 30.03.2010
comment
Я использую SimpleAdapter и даю своим объектам коллекции возможность возвращать представление себя в виде списка‹? расширяет Map‹String, ?›› для конструктора SimpleAdapter, что включает в себя копирование большого количества данных, потребление процессорного времени и создание мусора. Это может иметь или не иметь значения для любого данного приложения. - person CommonsWare; 30.03.2010
comment
Я внимательно слежу за подобными вещами и кеширую результаты таких вызовов, поэтому я вряд ли думаю, что использование такой удобной функции, как эта, приведет к значительному снижению производительности памяти или процессора. Это поднимает вопрос, на который, возможно, вы можете ответить. Если я заполняю HashMap, и все мои ключи являются инициализированными строковыми переменными, а все мои значения являются строковыми свойствами инициализированных объектов, вызывая map.put(key, value), разве я не просто передаю указатели, а не создаю тонну новых объекты (мусор)? Я бы предположил, что я недостаточно хорошо знаю Java, чтобы ответить на этот вопрос для себя. - person Rich; 30.03.2010
comment
Привет, Рич. Мне также нравится подход, при котором пользовательский интерфейс не зависит от того, откуда поступают данные, и код курсоров в пользовательском интерфейсе тоже выглядит уродливым, но я могу найти пару причин, почему они необходимы. Во-первых, это наиболее эффективный способ связывания данных с такими вещами, как ListViews. Во-вторых, чтобы преобразовать в коллекцию, вам нужно перебирать курсор линейно, O(n), создавать по одному объекту на строку, чего не было бы в курсоре, и GC должен будет собрать их в какой-то момент, но самое главное , вы загружаете всю свою коллекцию в память. Курсоры удерживают только текущую строку. - person palako; 14.10.2010

Ответы 4-летней давности. Я думаю, что теперь у нас достаточно мощности процессора, чтобы справиться с большим количеством задач. Моя идея заключалась бы в том, чтобы работать только с POJO и ArrayList; и расширение CursorLoader для сопоставления курсора с POJO в фоновом режиме и доставки массива в активность;

если вы не запрашиваете сотни строк, но тогда, как часто вы это делаете по сравнению с удобством использования POJO, геттеров и сеттеров

person urSus    schedule 02.04.2014