История неуспеха, или почему в Ленточке до сих пор нет свайпа между постами (UPD: уже есть)

Jun 27, 2013   #без категории 

Начну с того, что кратко расскажу о курсорах и адаптерах в Android.

Есть такая полезная штука — адаптер. Зачем он нужен?
Допустим, у нас есть простой список. ListBox/ListView/whatever. Как ни назови, список есть список. Это может быть список SMS-сообщений, это может быть список покупок на ближайший день рождения, а может быть массив простых чисел от 2 до 5.

Так вот наполнять его руками не круто.
Раньше было принято как?

ListBox.addItem("item1")
ListBox.addItem("item2")
etc.

Например, так было в Visual Basic, когда я им ещё увлекался.
Гораздо удобнее привязать список к какому-то набору данных. Не обязательно к массиву. Это может быть динамический список. Например, страница результатов гугла. Или внеземной источник со списком неугодных жителей голубой планеты.
Вот этот произвольный источник данных мы назовём адаптером.
И будем писать:

listView.setAdapter(new GoogleResultsAdapter("keygen crack скачать бесплатно"))

Список может быть бесконечным и его необязательно инициализировать одномоментно целиком. Можно показывать по 3 результата, а остальные подгружать по необходимости. Ленивая загрузка.

А теперь задумаемся. Пусть есть большая и клёвая база данных, откуда хочется читать данные и выводить списком. Для получения какого-то списка из базы можно выполнить простой select-запрос.

SELECT title, body FROM messages_table WHERE username="id1"

Получим список всех сообщений для пользователя id1.
Такой объект запроса с возможностью итерирования по строкам ответа называется курсором. Вообще, это не андроид-специфичная вещь, а вполне себе известное понятие в базах данных. Его можно периодически обновлять, чтобы актуализировать данные, а можно данные из него также выводить. Удобным способом вывода данных из курсора будет адаптер. Таким образом можно показать результаты запроса в виде ListView.

Оба этих объекта успешно применяются, например, в Ленточке для вывода списка лент и списка постов. При изменении какого-то параметра, например, количества непрочитанных сообщений в фиде или статуса “прочитано/новое” поста, данные автоматически обновляются в курсоре и отображаются адаптером в списке. Получается как бы проекция таблицы результатов (и, возможно, даже не одной) на обычный компонент ListView.

Другим не менее прекрасным, но менее очевидным, применением является использование этих технологий в показе экрана текущего поста. При свайпе пальцем влево/вправо происходит переключение на следующий/предыдущий пост прямо на месте. Можно сказать, что это горизонтальный список с одним видимым элементом.
При прочтении сообщения или изменении других его метаданных статус сразу же отображается, так как список привязан к адаптеру, автоматически отслеживающему все изменения в данных курсора. Если вдруг фоновая часть приложения (сервис автоматического обновления, который я ещё не начинал делать) изменит какие-то данные в базе (загрузит и сохранит с сервера информацию о том, что пользователь отметил 1 и 4 посты как избранные, а 6 пост отметил непрочитанным), то это сразу отобразится пользователю.

Всё очень чудесно, а понимание того, как это устроено, а также использование этого доставляет как минимум удовольствие. Как максимум — новые проблемы.
Допустим, мы используем курсор, ссылающийся на непрочитанные посты, с запросом SELECT * FROM posts WHERE read=0. И просто показываем эти посты, позволяя их листать и переключаться между ними. Но. Есть одно но. Каждое открытие другого поста (простым движением пальца) отмечает его прочитанным (вполне логично, чтобы не заставлять пользователя каждый раз нажимать кнопку “да, я прочитал это, хочу дальше читать”). И курсор моментально на это реагирует. Из результатов запроса этот пост пропадает (ведь WHERE read=0), из текущего одноэлементного списка пропадает и приложению ничего не остаётся кроме как переключиться на следующий непрочитанный пост. Открыт новый пост — отмечаем прочитанным. Внимательный читатель может догадаться, что таким образом все новые посты через недолгий срок сами отметятся как прочитанные и пользователь не успеет ничего почитать. Грустно. Но именно на этом я сегодня зашёл в тупик.

Красивая технология — практически прямая проекция содержимого БД на UI — обернулась трагедией. И из-за этого пользователи Ленточки так и не получили ожидаемое обновление приложения =(
Будет, конечно, обновление. Но только придётся частично отказаться от такого подхода.
Тем не менее, я, ранее близко не прикасавшийся к курсорам и адаптерам, в восторге от того, как заранее продуманная и старательно написанная мелочь наткнулась на не ожидаемое мной поведение. Это было слишком внезапно, но невероятно интересно. Отрицательный результат — тоже результат.

Так что добра тебе, дорогой читатель. Не забывай о том, что надо почаще думать головой и более тщательно продумывать последствия, даже если всё заранее слишком очевидно и просто. Я ещё учусь, наступаю на грабли, тыкаюсь носом в подводные камни. Но каждый день узнаю что-то новое и интересное. Я джуниор, мне можно ^_^

А вообще я слоупок и за последнюю неделю мало чего сделал по Ленточке. Зато появилась авторизация через аккаунт Яндекса, если установлено хотя бы одно из приложений, требующих входа в аккаунт (типа Яндекс.Почты, Яндекс.Диска или Яндекс.Музыки). Но это уже совсем другая история :)

comments powered by Disqus