Pull to refresh

Хабрачтец или как я сделал этим летом

Reading time 8 min
Views 5.6K
Здравствуйте!

Вдохновленный постами о том, что нужно начать делать и все получится, в данном материале я хотел бы поделиться рассказом о результате многочисленных вдохновений и моём опыте разработки приложения для ОС Андроид. Постараюсь описать процесс от возникновения идеи до ее реализации.

Прошедшее лето подарило мне два с половиной месяца полной свободы, половину которых я потратил на написание программы. Я не то, чтобы новичок – мой диплом был первым достаточно серьезным проектом, однако, думаю, что именно данное приложение принесет мне славу будет вам интересно.
Что у меня было исходного на тот момент:
  • Время
  • Galaxy Tab
  • Eclipse IDE с ADT plugin

Казалось бы. Причем тут Хабр?

А вот причем. Вашему вниманию — Хабрачтец:

image

Как я уже упомянул – в конце июня сего года мне уже предстояли пара месяцев свободных от какой-либо занятости. И я завел себе привычку, просыпаясь с утра, открывать на планшетнике пару тройку новостных приложений, заботливо предложенных Маркетом, и внимательно их изучать. А что, очень удобно. Чашка дымящегося кофе, вид с балкона, бутерброд и домашний беспроводной вай-фай отныне делали начало моего дня.

Свою ложку дёгтя добавило только отсутствие Хабраклиента – приходилось открывать Оперу, идти на сайт, скроллить, подгонять… Не то, чтобы прям неудобно, но все же одним пальцем не так-то просто понажимать, да позумить, особенно с чашкой кофе в руке. Где-то в один из таких моментов я подумал. И решил. Попытаться написать клиента для сайта по подобию уже имевшихся у меня приложений.

Что было исходного:
  • Веб страница Хабра со всеми вытекающими
  • Опыт написания дипломной работы, представляющая собой связку сервер – клиент, где клиент (барабанная дробь), да да – Андроид приложение
  • Эклипс и плагины
  • Гэлэкси Тэб

Что ставилось в задачу:
  • Разбор страницы на составляющие: Посты, Вопросы, События
  • Каждый элемент, будь то пост или вопрос, должен содержать все то, что содержит оригинал на сайте
  • Возможность добавлять в избранное и хранить на устройстве
  • Несложный интерфейс, сохраняющий стилистику и структуру оригинала
  • И наконец изюминка – режим «Сохранения на будущее» (думаю, что суть ясна, объясню чуток позже)

Исходный материал помноженный на четыре недели (имеется ввиду действительно рабочие дни из тех двух месяцев – так-то я еще на море съездил) принес свои плоды – теперь я могу наслаждаться чтением Хабра в любом месте, где есть интернет.

Далее немного деталей.

Данные и их обработка

Технически приложение достаточно простое. У меня естественно не было доступа к API Хабра. Пришлось вертеться. Итак, поэтапно.
Хабрачтец делает запрос на адрес хабра и получает HTML код с помощью HttpUrlConnection. Данная операция по понятным причинам асинхронна – она не должна и потому не блокирует интерфейс. Последовательность действий проста – нажатие кнопки, запуск фоновой задачи, подключение к Хабру, получение кода и передача его заинтересованной Activity в виде объекта String, вложенного в специальный Intent, посредством оповещения (Broadcast). Ничего вроде особенного.

Для гурманов: Однако в описанной выше последовательности была загвоздка. Для передачи данных внутри приложения (и вообще системы) используются объекты-намерения – Intent, пересылаемые в оповещениях – Broadcast. Так вот. Пару раз внутреннее содержимое постов не хотело грузится. Т.е. даже по логам было видно, что приложение нашло Хабр, загрузило код страницы, но дальше… ничего. Вообще. Тишина. Приложение не зависало, но и ничего не происходило. Перезапуски не помогали. Содержимое не появлялось. Проблема была оставлена до лучших времен и объяснилась практически случайно.

Дело в том, что все новые и свежие посты грузились легко и непринужденно. А вот почитать что-нибудь постарше и с большим количеством комментариев было уже нельзя. Внимательное(!) чтение логов выявило странную строку о системной ошибке – !!!FAILED BINDER TRANSACTION!!! Сложно не заметить, правда? Вот я и не заметил. Единственная строка, тут же забиваемая другим «мусором». В ней и крылась проблема. Гугление показало, что подобное возникает в случае, если данные используемые для передачи превосходят некий лимит. Начал мерять размер строки – 600 000 знаков. А ведь там даже 100 комментариев не было! В общем, добавил очистительные процедуры, провел несколько проб и выяснил предел, равный 250 тысячам знаков в строке. Сейчас, если даже после чистки размер превышен, строка обрезается и… не все комментарии будут доступны (*плачет*).
Решить, проблему можно относительно легко, хотя бы передавать данные в пару этапов. Думаю, что она будет решена в следующем обновлении.


Далее HTML код веб-страниц с сайта обрабатывается на интересующие составляющие. Для этого используется библиотека Jsoup – штука отличная, позволяющая извлекать все необходимые данные по указанным тэгам и аттрибутам. Достаточно одной таблэтки строки:
Document document = Jsoup.parse(html);

Ну а дальше уже разбор на элементы.

Для гурманов: полученный после однострочной обработки объект класса Document предоставляет два варианта получения необходимых внутренних элементов. Первый с помощью «обычных» геттеров:
//Так например извлекаются все посты с главной главной страницы
Elements contentElements = document.getElementsByAttributeValueContaining("class","hentry");

Второй с помощью более удобного общего метода select()
//То есть так:
document.select(".page-navigation .info-text [class*=live] ");

Как видно второй вариант куда более удобен, позволяя сократить количество кода. Одной строкой ищутся элементы с аттрибутом class равным «page-navigation» и «info-text», а также содержащим слово «live». Однако существенных преимуществ в производительности замечено не было.

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

После обработки HTML создается отдельный объект соответствующего типа будь то пост, вопрос или событие, которые в последствии записываются в соответствующую таблицу с ключом = id. Таблицы сделаны статичными и доступны для всего приложения посредством DataManager — класса-синглтона. В памяти сохраняются с помощью пакета java.io и Context.getDir().

Для гурманов: думаю, что Андроид-разработчики, прочитав предыдущие строки, многозначительно хмыкнут и подумают про себя, что-нибудь вроде «тоже мне...». Дело в том, что не стоит (и я это уже понял) использовать в данном случае java.io, а естественно лучше базу данных. Я ловил кучу ошибок связанных как раз с ошибками в чтении и записи, ведь в Java объекты передаются по ссылке, которые нужно постоянно обновлять, что разумеется можно банально забыть сделать. Ну и разумеется скорость, теряемая на проверки и обновления не особо доставляет радости и прибавляет скорости работы приложению, причем снижение в данном случае линейно и зависит от числа запоминаемых элементов. Каюсь, делал как проще и быстрее. Не факт, что стало быстрее и уж точно не стало проще.
В общем будет переделано. 100%.


С отображением основного текста поста (и любого другого материала) была небольшая заминка. Многие приложения используют для этих целей WebView – специальный вид для веб страниц, очень мощный инструмент, способный подгружать материал из сети, отображать уже существующий. Для меня его «недостатком» стала мощь. К примеру, аннотации реализованы как выпадающие элементы списка – использование WebView потребовало бы больше вычислительных ресурсов. Поэтому выбор пал на TextView, который получал от Html.fromHtml(…) метода объект Spannable. Вполне себе эффективный способ, позволяющий при желании с помощью TagHandler настраивать отображение нужных тэгов (например «code» — мой любимый) и подгружать картинки с ImageGetter.

Для гурманов: О картинках и ImageGetter. По умолчанию загрузка в фоновом режиме не возможна – интерфейс блокировался. Решается легко и просто – фоновое задание, загрузка в кэш-директорию и обновление TextView по окончании.
Почему-то проходит не без проблем. Некоторые картинки, в основном с внешних ресурсов, не habrastorage, подгружаются через одну. Причину пока отловить не удалось. Работаю над этим.


Плюшки

Режим редактирования позволяет указать интересующие материалы и загрузить их содержимое. Программа запишет все в память, и в последствии можно будет почитать их, например по дороге на работу в метро.
Возможно чистить как целиком все списки, сразу всю ленту, избранное, а можно и по несколько разрозненных на выбор.
Если не хочется тратиться на трафик, да и интересная ссылка видна в аннотации к посту – долгое нажатие поможет отобразить список всех доступных ссылок. То же самое действительно и для ссылок в ответах и комметариях.
По желанию есть возможность отослать ссылку на пост себе на почту. Мне не нужно в принципе – может понадобиться людям с аккаунтом, чтобы прокомментировать понравившийся пост позднее. В будущем доделаю-таки добавление событий в календарь, пока в альфа версии.
Что касается отображения видео – заменяю его на обычную ссылку. Единственное, что не получается представить – это Подкасты. Честно говоря, пока даже не пытался. Возможно все-таки придется вернуться ко WebView.
И, конечно, есть загрузка без картинок для «очень» мобильных сетей.

Интерфейс

Основной вид программы, как видно из первого скриншота – это вкладки, повторяющие три основных и наиболее интересных (мне – под себя ведь писал) раздела Хабра. Ближе к концу процесса разработки была идея использовать слайд эффект – переключение между разделами с помощью скользящего жеста пальцем. Однако желание больше соответствовать оригиналу пересилило. К тому же основной вид и его был к тому времени уже настолько сложен, что потребовал бы приличного времени на переделку.
Цвета, использованные в программе, как и расположение основных элементов – даты, имени автора, темы взяты тоже с хабра. Картинки и иконки (за исключеним тех, что в меню – их притырил из sdk) рисовал сам. И, да… Я – не дизайнер (*горестно вздыхает*). Но старался, что уж тут.

Для гурманов: Все-таки не стоит делать столь насыщенных деталями элементов списков. Тормозит прилично, хоть граница «ну невозможно этим пользоваться» и не была пересечена. Пользуюсь. Решением подобной проблемы может стать, к примеру, специальный адаптер с кэшированием, подгружающий и удаляющий элементы по мере их появляения на экране устройства. Например такой.

Дальше — меньше букв, больше скриншотов:

image
image
image
image
image

Производительность

В виду особенностей техники (Galaxy Tab у меня без 3G, модель P1010) работал исключительно с вай фаем. Дома линия в 8 Мбит. В нескольких кафе субъективно меньше. Разницы особо не ощущал.
Главный вопрос – сколько потребляется трафика. Ответ – столько же, сколько на доступ к Хабру через обычный браузер.
Не менее главный вопрос – как быстро все работает. Ответ – достаточно быстро. Как уже упоминалось, для новых постов, вопросов и событий – обработка проходит быстро, максимально до 2-3с, по измерениям. Если много комментариев, да еще и материал объемен – может быть больше. Рекорд по измерениям – 10с. Прилично, да? В защиту скажу, что это действительно было один раз. В среднем – менее 5 секунд.
Цифры действительны для отображения текста, картинки грузятся асинхронно и появляются после загрузки, поэтому влияние на чтение не учитывал.
Скорость прокрутки списков – ListView – стоит отдельного упоминания. Подтормаживает, но терпимо. Работал со списками до 70 элеметов, больше вроде не было необходимости.

Выводы

Процесс написания программы офигителен офигителен. Действительно, писать мне понравилось очень, даже, наверное, больше чем собственно пользоваться приложением. Все-таки программисты – творческие люди, чтобы там ни говорили. Это действительно эйфория – написать пару строк и увидеть результат.
Я попробовал себя в «теоретической» роли фрилансера. И, скажу вам, не фонтанирует. Дома, один с компом и телевизором, создающим фон, практически весь день (всю рекламу уже выучил). В том же офисе хоть какое-то общение ведь бывает. Живое, причем. Обедать – один, ведь все на работе. А если еще и наткнуться на проблему интересную, так она и в выходные может не отпустить. Я себя на мыслях о проблеме с количеством знаков в строке даже в кино ловил. Что там – я ее отцу и подруге объяснял! Про интенты, броадкасты. А он у меня – металлург, она – биолог…
Мне, надеюсь, удалось применить на практике те знания, что я получил в университете. И практические, и теоретические. И, конечно, приобрести новые. А главное узнать про некоторые свои недостатки. Как, например, «сделаю, чтоб работало» или написать кучу полезных методов, а потом все забыть и все равно заново писать код. Каюсь, подхрамывала и общая организация процесса.

Главное

Главное, что я для себя понял. Любому проекту (не автору даже) необходимо постоянно вдохновляться, чтобы расти и улучшаться дальше. Источником вдохновения может быть что угодно – перспективы денежные, моральные, конкурентные, банально по работе надо и т.п. Когда проект начинает выполнять свои задачи, причем удовлетворяя всех – и авторов, и пользователей – его развитие прекращается. Для Хабрачтеца я – автор и единственный на данный момент пользователь, и меня в нем все устраивает. Но я не хотел бы, чтобы он прекратил свое развитие. Именно поэтому, я рассказал о нем вам.
Итак, вам слово.
Tags:
Hubs:
+45
Comments 25
Comments Comments 25

Articles