Урок 136. CursorLoader

Обсуждение уроков
Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Урок 136. CursorLoader

Сообщение Viewer » 02 июн 2014, 12:01

Что конкретно?

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

belant
Сообщения: 5
Зарегистрирован: 02 июн 2014, 10:14

Re: Урок 136. CursorLoader

Сообщение belant » 02 июн 2014, 13:46

Viewer писал(а):
belant писал(а):В уроке есть проблема. При повороте экрана во время работы loadInBackground будет вылетать исключение, т.к. лоадер восстановит объект BD, а база уже закрыта в onDestroy. Пока при сохранении состояния сохраняю признак выполняется ли loadInBackground, а при загрузке перезапускаю запрос, что не есть гуд. Кто знает как обойти эту проблему?
Есть стандартное решение - SQLiteOpenHelper (на сайте во всех уроках работа с БД построена через него) и все вопросы отпадут. При правильном использовании SQLiteOpenHelper берет на себя не только функции создания/обновления БД, но и все диспетчерские функции работы с БД - когда нужно сам открывает или закрывает подключения к БД, вам не нужно будет забивать этим голову.
Вам нужно только забыть про прямые обращения к БД, в частности, не нужно непосредственно открывать и закрывать подключения к БД (через методы контекста), а только через методы SQLiteOpenHelper
поясните кодом как надо? Я понимаю в этом уроке тоже все через хелпер, но при повороте во время фоновой операции будет исключение, я проверял.

belant
Сообщения: 5
Зарегистрирован: 02 июн 2014, 10:14

Re: Урок 136. CursorLoader

Сообщение belant » 02 июн 2014, 15:03

Поясню подробнее.
Если выполнять урок как есть, то при повороте во время фоновой операции получаем
06-02 11:48:00.357: E/AndroidRuntime(2180): java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
в scAdapter.swapCursor(cursor);

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

Код: Выделить всё

   @Override
    public Cursor loadInBackground() {
        try {
            TimeUnit.SECONDS.sleep(3);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
      Cursor cursor = db.getAllData();
      return cursor;
    }
то при повороте экрана на паузе получим на Cursor cursor = db.getAllData();
06-02 11:40:36.881: E/AndroidRuntime(2060): Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase

насколько я понял, это присходит т.к. в OnDestroy вызывается db.close() , а в OnCreate создается новый объект DB с новым хелпером и пр., но лоадер восстанавливает старую ссылку

Что не так в примере и как сделать правильно, чтобы не возникало исключений?

belant
Сообщения: 5
Зарегистрирован: 02 июн 2014, 10:14

Re: Урок 136. CursorLoader

Сообщение belant » 02 июн 2014, 17:25

Все работает, если не делать close для хелпера в OnDestroy. Но правильно ли это? Судя по коду SQLiteOpenHelper он не закрывает сам подключения к БД, там просто есть метод close, который нужно вызывать явно. Но если так, то когда его вызывать??? Или все таки есть где то вызов close хелпера?

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Урок 136. CursorLoader

Сообщение Viewer » 03 июн 2014, 11:56

насчет close все далеко не однозначно, особенно для ContentProvider, вообще даже сами разработчики android рекомендуют явно не закрывать БД в провайдерах.
A content provider is created when its hosting process is created, and remains around for as long as the process does, so there is no need to close the database -- it will get closed as part of the kernel cleaning up the process's resources when the process is killed.
- показать цитируемый текст -
--
Dianne Hackborn
Android framework engineer
hac...@android.com

https://groups.google.com/forum/#!msg/a ... am4Q8-cqQJ
Я так тоже как-то раз об это споткнулся, потом вообще забыл про close и не парился больше с ним.
Главное что он не дает больших утечек памяти и не удерживает процесс приложения (или провайдера) в памяти, когда он уже не нужен, а сборщик мусора нормально справляется с этим.

belant
Сообщения: 5
Зарегистрирован: 02 июн 2014, 10:14

Re: Урок 136. CursorLoader

Сообщение belant » 03 июн 2014, 13:53

Получается (сужу еще по ряду примеров, например, из книги "Брайн Харди, Билл Филлипс - Программирование под Android" глава 35) действительно в OnDestroy закрывать соединение с БД не нужно, иначе работать после смены конфигурации не будет. Плюс еще момент - создание хелпера как в уроке приводит к тому, что мы будем иметь два объекта после смены конфигурации - один, который восстанавливает лоадер и один новый, который не будет использоваться до тех пор пока не будет пересоздан лоадер, и мы ему заново не передадим ссылку на хелпер из активности. В книге хелпер хранится вообще в синглтоне, т.е. создается один раз за время жизни приложения.

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Урок 136. CursorLoader

Сообщение Viewer » 03 июн 2014, 14:05

belant писал(а): В книге хелпер хранится вообще в синглтоне, т.е. создается один раз за время жизни приложения.
Это вполне нормальный вариант, еще лучше поместить его в ContentProvider, который тоже не зависит от жизненного цикла ваших Activity.

zagayevskiy
Сообщения: 1
Зарегистрирован: 11 июн 2014, 12:39

Re: Урок 136. CursorLoader

Сообщение zagayevskiy » 11 июн 2014, 12:44

Привет всем.
Прочитал урок, имеется вопрос:
Подключение к бд открывается в onCreate, закрывается в onDestroy. А что, если я используют это в двух разных активити, первая из которых стартует вторую? Будет ли ошибка при попытке повторного открытия бд?
Другой вопрос из этой же темы - что, если onDestroy не произойдет? Что будет с подключением?

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Урок 136. CursorLoader

Сообщение Viewer » 11 июн 2014, 12:58

zagayevskiy писал(а):Привет всем.
Подключение к бд открывается в onCreate, закрывается в onDestroy. А что, если я используют это в двух разных активити, первая из которых стартует вторую? Будет ли ошибка при попытке повторного открытия бд?
Почитайте последние посты этой темы, мы как раз вопросы закрытия базы и обсуждали.

bagrusss
Сообщения: 22
Зарегистрирован: 08 дек 2013, 00:17

Re: Урок 136. CursorLoader

Сообщение bagrusss » 08 июл 2014, 23:26

Такой вопрос: если у меня в базе данных в поле хранится ссылка на картинку в файловой системе в виде строки и мне необходимо проверить существование картинки в ФС и установить эту картунку в ImageView элемента списка, как быть?

Viewer
Сообщения: 180
Зарегистрирован: 30 апр 2014, 11:42

Re: Урок 136. CursorLoader

Сообщение Viewer » 09 июл 2014, 04:27

bagrusss писал(а):Такой вопрос: если у меня в базе данных в поле хранится ссылка на картинку в файловой системе в виде строки и мне необходимо проверить существование картинки в ФС и установить эту картунку в ImageView элемента списка, как быть?
Получить ID картинки из ресурсов и использовать его
int imageId = getResources().getIdentifier("imageName", "drawable", null);

bagrusss
Сообщения: 22
Зарегистрирован: 08 дек 2013, 00:17

Re: Урок 136. CursorLoader

Сообщение bagrusss » 09 июл 2014, 10:51

Получить ID картинки из ресурсов и использовать его
int imageId = getResources().getIdentifier("imageName", "drawable", null);
Дело в том, что картинка хранится не в ресурсах, а на карте памяти или внутренней памяти.

Код: Выделить всё

    // формируем столбцы сопоставления
    String[] from = new String[] { DB.COLUMN_IMG, DB.COLUMN_TXT };
    int[] to = new int[] { R.id.ivImg, R.id.tvText };

    //или все таки свой кастомный адаптер делать?
    scAdapter = new SimpleCursorAdapter(this, R.layout.item, null, from, to, 0);

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Урок 136. CursorLoader

Сообщение KamiSempai » 09 июл 2014, 11:46

bagrusss писал(а):Такой вопрос: если у меня в базе данных в поле хранится ссылка на картинку в файловой системе в виде строки и мне необходимо проверить существование картинки в ФС и установить эту картунку в ImageView элемента списка, как быть?
Без кастомного адаптера не обойтись. Картинку можно поставить так:
[syntax=java]Bitmap bitmap = BitmapFactory.decodeFile(imageFileName);
if(bitmap != null)
imageView.setImageBitmap(bitmap);[/syntax]
Советую декодировать изображение в отдельном потоке, и ужимать его до размеров View так как декодирование может занимать достаточно большое время, что вызовет тормоза при прокрутке.

Сжать картинку можно так:
[syntax=java]Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, false);
bitmap.recycle(); // От старой картинки лучше избавиться, что бы не занимала место в памяти.[/syntax]
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Artemko
Сообщения: 26
Зарегистрирован: 16 июл 2012, 15:09

Re: Урок 136. CursorLoader

Сообщение Artemko » 13 июл 2014, 14:59

как обновить cursorloader, если я хочу заполнить список использую другой cursor

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Урок 136. CursorLoader

Сообщение Foenix » 13 июл 2014, 15:07

swapCursor?
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

Ярослав
Сообщения: 4
Зарегистрирован: 15 июл 2014, 15:07

Re: Урок 136. CursorLoader

Сообщение Ярослав » 15 июл 2014, 15:22

Подскажите пожалуйста.
Приложение делает фотографии, и в БД записывается полный путь к фотографиям. С помощью данного примера, выводятся в ListView. Проблема в том, что при выводе даже небольшого кол-ва фотографий (от 7 и больше) прокрутка этого ListView начинает жутко тормозить. Можно их обработать до того как они попадут непосредственно в ListView? Сжимать сразу когда делается фото неподходит, т.к. в дальнейшем планирую при нажатии на фото в ListView выводить оригинал фото в дрогой активности. Может нужно использовать кастомный адаптер?

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Урок 136. CursorLoader

Сообщение altwin » 15 июл 2014, 15:33

Ярослав писал(а):Подскажите пожалуйста.
Приложение делает фотографии, и в БД записывается полный путь к фотографиям. С помощью данного примера, выводятся в ListView. Проблема в том, что при выводе даже небольшого кол-ва фотографий (от 7 и больше) прокрутка этого ListView начинает жутко тормозить. Можно их обработать до того как они попадут непосредственно в ListView? Сжимать сразу когда делается фото неподходит, т.к. в дальнейшем планирую при нажатии на фото в ListView выводить оригинал фото в дрогой активности. Может нужно использовать кастомный адаптер?
существует такое понятие, как pagination, подразумевающее ограничение выдачи с последующей возможностью пролистывания( помоему для определения -это коряво звучит :) ) и применимо оно к любой коллекции. Вам нужно идти в сторону custom listview.
Изображение

Аватара пользователя
altwin
Сообщения: 1951
Зарегистрирован: 13 ноя 2013, 14:46

Re: Урок 136. CursorLoader

Сообщение altwin » 15 июл 2014, 15:34

Ярослав писал(а):Может нужно использовать кастомный адаптер?
true
Изображение

Ярослав
Сообщения: 4
Зарегистрирован: 15 июл 2014, 15:07

Re: Урок 136. CursorLoader

Сообщение Ярослав » 15 июл 2014, 15:36

Благодарю. Голову уже сломал. Спасибо за направление, буду искать!

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Урок 136. CursorLoader

Сообщение KamiSempai » 15 июл 2014, 15:47

altwin писал(а):существует такое понятие, как pagination, подразумевающее ограничение выдачи с последующей возможностью пролистывания( помоему для определения -это коряво звучит :) ) и применимо оно к любой коллекции. Вам нужно идти в сторону custom listview.
Это, что, тролинг???

Ярослав, нужно делать кастомный адаптер и сжимать изображения перед отображением в списке.
Это должно помочь: viewtopic.php?f=3&t=2961&p=32859#p32596
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Ответить