Listview не перечисляет значения базы данных с помощью CursorAdaptor [дубликат]

Хотя переменные, определенные внутри области функции, не могут быть доступны извне, это не означает, что вы не можете использовать их значения после завершения этой функции. PHP имеет хорошо известное ключевое слово static, которое широко используется в объектно-ориентированном PHP для определения статических методов и свойств, но следует иметь в виду, что static также может использоваться внутри функций для определения статических переменных.

Что это за «статическая переменная»?

Статическая переменная отличается от обычной переменной, определенной в области функции, в случае, если она не потеряет значение, когда выполнение программы выходит из этой области. Давайте рассмотрим следующий пример использования статических переменных:

function countSheep($num) {
 static $counter = 0;
 $counter += $num;
 echo "$counter sheep jumped over fence";
}

countSheep(1);
countSheep(2);
countSheep(3);

Результат:

1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence

Если бы мы определили $counter без static, то каждый раз эхо-значение будет будет таким же, как параметр $num, переданный функции. Использование static позволяет построить этот простой счетчик без дополнительного обхода.

Использование прецедентов статических переменных

  1. Чтобы сохранить значения между последовательными вызовами функции.
  2. Сохранять значения между рекурсивными вызовами, когда нет пути (или нет цели) для передачи их в качестве параметров.
  3. К кеш-значению, которое обычно лучше извлекать один раз. Например, результат чтения неизменяемого файла на сервере.

Трюки

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

Статическая переменная может быть определена только как скалярным или как скалярное выражение (с PHP 5.6). Присвоение других ценностей неизбежно приводит к отказу, по крайней мере, на момент написания этой статьи. Тем не менее вы можете сделать это только на следующей строке вашего кода:

function countSheep($num) {
  static $counter = 0;
  $counter += sqrt($num);//imagine we need to take root of our sheep each time
  echo "$counter sheep jumped over fence";
}

Результат:

2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence

Статическая функция «разделена» между методами объектов тот же класс. Это легко понять, просмотрев следующий пример:

class SomeClass {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$object1 = new SomeClass;
$object2 = new SomeClass;

$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother

Это работает только с объектами того же класса.

Является ли статическая переменная единственным способом сохранить значения между вызовами функции?

Другим способом сохранения значений между вызовами функций является использование замыканий. Закрытие было введено в PHP 5.3. В двух словах они позволяют ограничить доступ к некоторому набору переменных внутри области функций другой анонимной функцией, которая будет единственным способом доступа к ним. Быть в закрывающих переменных могут имитировать (более или менее успешно) концепции ООП, такие как «константы класса» (если они были переданы в закрытии по значению) или «частные свойства» (если они переданы по ссылке) в структурированном программировании.

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

68
задан Deepzz 19 February 2015 в 05:59
поделиться

8 ответов

Еще один способ справиться с отсутствием столбца _id в таблице - написать подкласс CursorWrapper, который при необходимости добавит столбец _id.

Это имеет то преимущество, что не требует каких-либо изменений в таблицах или запросов.

Я написал такой класс, и если это интересно, его можно найти в https://github.com/cmgharris/WithIdCursorWrapper

0
ответ дан cmgharris 22 August 2018 в 03:40
поделиться

Это ответил , и я хотел бы сделать его более всеобъемлющим здесь.

SimpleCursorAdapter требует, чтобы в результирующем наборе Cursor был включен столбец с именем точно «_id». Не спешите изменять схему, если вы не указали столбец «_id» в своей таблице. SQLite автоматически добавляет скрытый столбец с именем «rowid» для каждой таблицы. Все, что вам нужно сделать, это просто выбрать rowid явно и псевдоним как «_id».

SQLiteDatabase db = mHelper.getReadableDatabase();      
Cursor cur =  db.rawQuery( "select rowid _id,* from your_table", null);
101
ответ дан Community 22 August 2018 в 03:40
поделиться
  • 1
    или выберите id как _id – max4ever 19 January 2012 в 14:35
  • 2
    лучший ответ i для решения проблемы. – Mihir Palkhiwala 10 April 2012 в 12:46
  • 3
    Как насчет переопределения getItemId и предоставления моего собственного идентификатора? Может ли это решить проблему? – BornToCode 6 June 2012 в 10:58
  • 4
    Великий!! это сработало для меня ... Спасибо .. @ Тим Ву :) – swiftBoy 20 July 2012 в 14:13
  • 5
    @ max4ever имеет лучший ответ. Это идеальное решение этой проблемы. Не нужно начинать создавать ненужные столбцы _id в вашей базе данных – Mike Baxter 2 August 2013 в 12:24

Да, я также изменяю строковый запрос SELECT, чтобы исправить эту проблему.

String query = "SELECT t.*,t.id as _id FROM table t "; 
20
ответ дан Deepzz 22 August 2018 в 03:40
поделиться
  • 1
    Большой! Благодаря тонну. Сохраняла мою базу данных из-за искажения с помощью _id. Спас день – TryinHard 12 September 2016 в 17:11
  • 2
    @TryinHard: Добро пожаловать :-) – Deepzz 16 September 2016 в 06:25

Если вы прочитали документы на sqlite, создание любого столбца типа INTEGER PRIMARY KEY будет внутренне псевдонимом ROWID, поэтому не стоит добавлять псевдоним в каждый SELECT, отклоняясь от любых общих утилит, которые могут воспользоваться преимуществами что-то вроде перечисления столбцов, определяющих таблицу.

http://www.sqlite.org/autoinc.html

Это также более прямолинейно использовать это как ROWID вместо опции AUTOINCREMENT, которая может привести к тому, что _ID может отклоняться от ROWID. Привязывание _ID к ROWID означает, что первичный ключ возвращается из insert / insertOrThrow; если вы пишете ContentProvider, вы можете использовать этот ключ в возвращаемом Uri.

0
ответ дан Eric Woodruff 22 August 2018 в 03:40
поделиться

Я вижу, что в документации для CursorAdapter указано:

Курсор должен содержать столбец с именем _id или этот класс не будет работать.

SimpleCursorAdapter является производным классом, поэтому представляется, что это утверждение применяется. Однако заявление технически неверно и несколько вводит в заблуждение новичка. Набор результатов для курсора должен содержать _id, а не сам курсор. Я уверен, что это понятно для администратора баз данных, потому что эта краткая документация им понятна, но для этих новичков, будучи неполным в заявлении, вызывает путаницу. Курсоры подобны итераторам или указателям, они не содержат ничего, кроме механизма трансверсации данных, они не содержат самих столбцов.

Документация Loaders содержит пример, где можно видеть, что _id включен в параметр проекции.

static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
    Contacts._ID,
    Contacts.DISPLAY_NAME,
    Contacts.CONTACT_STATUS,
    Contacts.CONTACT_PRESENCE,
    Contacts.PHOTO_ID,
    Contacts.LOOKUP_KEY,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // ...
    return new CursorLoader(getActivity(), baseUri,
            CONTACTS_SUMMARY_PROJECTION, select, null,
            Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
146
ответ дан JJD 22 August 2018 в 03:40
поделиться
  • 1
    Я рекомендую, чтобы оператор в документации записывался как «Целочисленный набор результатов для курсора должен содержать столбец с именем« _id ». В противном случае будет создано исключение RuntimeException. & Quot; Это будет менее запутанным и правильным. – user405821 29 July 2010 в 17:02
  • 2
    @ user405821 - Спасибо, человек - этот парень не отметил ваш ответ как правильный - но это было отличное дополнение к части Android, которая плохо документирована. +1 – tpow 11 December 2010 в 16:55
  • 3
    Я сделал заметку в документах android, используя sidewiki Google. sidewiki идеально подходит для такого рода вещей, и я надеюсь, что все больше людей используют его в сочетании с документацией по Android. [Д0] developer.android.com/reference/android/widget/… – Ben H 28 October 2011 в 23:21
  • 4
    О, человек, это потрясающая документация для Android SDK + для вас! Большое вам спасибо за ответ. Я потратил больше часа, пытаясь понять, в чем проблема. – the_dark_destructor 3 July 2013 в 10:16
  • 5
    Благодаря! В моем случае ошибка возникла из-за проблемы с верхним регистром v / s в нижнем регистре. – Vish 8 January 2016 в 10:05

Что решило мою проблему с этой ошибкой, так это то, что я не включил столбец _id в мой запрос БД. Добавив это, я решил проблему.

7
ответ дан Tapan Chandra 22 August 2018 в 03:40
поделиться
  • 1
    Это когда все решения не могут решить проблему. Последнее средство ко всему. – tom_mai78101 19 June 2013 в 15:03

Это, вероятно, уже не актуально, но сегодня я столкнулся с одной и той же проблемой. Оказывается, имена столбцов чувствительны к регистру. У меня был столбец _ID, но Android ожидает столбец _id.

6
ответ дан zmbq 22 August 2018 в 03:40
поделиться
  • 1
    Это непростая ошибка; официальная документация говорит использовать _ID. – user 26 December 2013 в 17:49
20
ответ дан Deepzz 5 November 2018 в 02:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: