23 ноября 2010

Про Андроид 2

Стравив в прошлый раз яд, я, видимо, должен сейчас сочиться миррой и благовониями, посмотрим.

Для начала я снова отошлю вас почитать три неплохие статьи на тему.

Первое, за что андроид может заслужить фавора - это открытость. Под этим я понимаю много разных вещей. Например, крайне широкие возможности для интеграции как с системой, так и с другими приложениями. Вот я сделал фото камерой и могу его теперь отправить в Gmail, Picasa, Twitter и кучу других приложений. Если я объявлю в своём приложении, что оно умеет принимать изображения - оно тоже окажется в этом списке. И обратно - чтобы реализовать кнопку "Share" мне не нужно волочить с собой библиотеку для Facebook, Twitter и прочего Вконтакта. Достаточно сделать один вызов к OS - она выберет те приложения, которые могут обработать то или иное содержимое. И, заметьте, только те приложения, которые установлены, которые пользователь сам себе поставил и, вероятно, где надо уже авторизован. При этом границы приложения пересекает только та информация, которой это приложение готово поделиться, никакого нарушения изоляции, sandboxing там не менее строгий. На том же механизме, например, реализована система плагинов к популярному приложению Locale - просто и красиво. Или интеграция в поиск по телефону. Хотите, чтобы ваши задачи из вашей новой ToDo'шечки отображались в результатах поиска - вы можете реализовать поддержку этого. Или возможность всё заменить - приложение для контактов, телефона, почтовый клиент, плеер, камеру, рабочий стол... тысячи их (замен стандартным вариантам).

Другое проявление открытости - доступность исходников. Это отдельная тема священных войн, открыт ли андроид в смысле отрытого ПО, но факт остаётся собой - исходники можно получить и пощупать, можно даже почитать. Увы, делать это иногда даже необходимо (про документацию см. пред. пост). Однако не стоит забывать о том, что в случае конкретных прошивок исходники могут не соответствовать реальности (см. пред. пост).

Неплохим моментом можно считать и Java в качестве основного языка разработки под платформу. Конечно, это выливается в некоторые неудобства типа внезапного как понос GC (и я бы не сказал, что следить за памятью приходится меньше, чем с Objective-C), однако есть и преимущества. Для всего существует библиотека на Java - почти аксиома. Да и сама Java тут вполне нормальная, и SDK работать должен на всех основных платформах (RIM, тут вам нужно начать икать втрое интенсивнее). И да, декларировать пять раз свойство не приходится - объявил поле и автоматически сгенерировал методы доступа (это в тему того, что язык хоть и не обладает такими красивыми концепциями как передача сообщений или необязательные методы в интерфейсе/протоколе, но не выглядит таким динозавром. Подробнее - по одной из ссылок). Опять же мощная поддержка со стороны IDE: десятки рефакторингов, сотни инспекций (в реальном времени, а не после компиляции), тысячи плагинов, навигация, документация и автодополнение - XCode даже не разгибается (что они сделали с документацией XCode?! раньше хоть как-то можно было пользоваться). Удобнее отладчик, можно подключиться к уже запущенному приложению, это отчасти компенсирует медлительность приложения с подключённым отладчиком - быстро дошли до исследуемого места и подключили. Логи лучше - уровни (от Debug до WTF), фильтры, лог сохраняется даже тогда, когда устройство не подключено к IDE и можно посмотреть его постфактум (впрочем, коллеги начали прикручивать отправку исключений в Redmine из iOS приложений по моим стопам , частично устранив этот недостаток iOS).

Интерфейс. Действительно очень мощная поддержка различных разрешений и диагоналей, что с одной стороны необходимость при том многообразии устройств, на которых андроид должен запускаться, с другой стороны никто так здорово это не сделал. Таких гибких менеджеров размещения у Apple я не видел, остальные меры для поддержания различных экранов (iPhone, iPad, iPhone 4) либо провальные либо неудобные, а RIM уже должна помереть от икоты. Достаточно гибкие встроенные виджеты, которые к тому же при некоторой подготовке так легко видоизменять и комбинировать в более сложные компоненты (NB. об этом тоже стоит написать). В общем, пока вы играете на этом поле - возможности очень широки.

Многозадачность. Она, конечно же, не такая, как мы привыкли на ПК, OS будет ограничивать (16 Мб! 21 век!) и следить за вами и отрубит голову при первом же подозрении. Но если играть по правилам - вы можете работать на переднем плане, в фоне, получать системные события и реагировать на них. Не возникнет той абсурдной ситуации, когда я хочу открыть почту, когда синхронизируется RSS читалка, и вынужден ждать. А ещё это многозадачность пользователя - он может переключаться с задачи на задачу, вызывая именно те окна различных приложений, которые нужны ему для продолжения его рабочего процесса (workflow). Об этом и кнопке "Share" в частности рассказано в этом видео с Google IO 09 с 10 минуты.
Потерпите этого чувака 4 минуты, он это покажет лучше, чем я. Ну и виджеты, которые могут дать вам моментальный обзор необходимой информации без жонглирования приложениями. Всё это грамотно организовано и работает одновременно, не мешая друг другу.

Распространение софта свободно и дико, как нравы в племени мумбо-юмбо. Можно в Android маркет выложить (приложение на устройстве будет доступно через минуту! даже через Jabber я услышал, как упала челюсть шефа, до этого несколько лет воевавшего с AppStore), можно в сторонние магазины, можно на своём сайте, да хоть в Dropbox - знай только ссылку давай. Маркет, конечно, предпочтительней по некоторым причинам - он самый крупный, он предустановлен на большинстве аппаратов, он позволяет чётко разделять приложения по используемому железу и версии прошивки, так что вы не увидите игру для акселерометра на планшете без него. Однако даже если пользователь поставил софт почтовыми голубями, то вы можете мягко направить его в маркет за обновлениями, и приложение "Маркет" начнёт само следить за обновлениями. И каждый раз перед обновлением не нужно будет вводить пароль (умри, Appstore!)

Есть Flash (с 2.2). Кому-то надо. Нет, не тормозит (там, где у меня есть 2.2, но это весьма шустрый аппарат, так что не показательно).

Закончу, пожалуй, действительно радостной новостью - приложение, работа над которым дала почву для этих постов, стало Today hot #1 на appbrain.com, в чём огромная заслуга команды и мой небольшой вклад.

Хорошего начала рабочей недели!

20 ноября 2010

Про Андроид

Я давно копил яд и тщательно сцеживал в баночку. Но сегодня есть повод наконец-то высказаться. Поводом стало интерью с Максом Хауэллом (Max Howell) оригинал, одним из разработчиков TweetDeck (маководам-гикам он также может быть известен как автор Homebrew) и некоторых других полезных проектов.

Практически со всем, что пишет Макс, я могу согласиться. "Debug cycles on Android take half a minute at least." Да, чёрт побери, с запуском приложения всё плохо, очень плохо. Варианта, как водится, два: эмулятор (а не симулятор, как для iPhone) и реальное устройство. Первый вариант отпадает сразу, потому что эмулятор жестоко медленный (отдельный пункт для злословия - зачем делать эмулятор, который по идее должен досконально воспроизводить работу эмулируемой сущности, если он этого не делает? А тормозит так, будто целый кластер эмулирует. Вот симулятор iPhone - тоже часть функционала можно протестировать только на устройстве, но то, что можно на симуляторе - можно очень быстро). Какое там быстродействие, достаточное, чтобы UI плавно следовал за пальцем! Шевелится - и ладно. В мусорку, годится только на первый день, пока не завезут девайс. Да и тогда между сохранением исходников и запуском программы стоят неповоротливые компилятор, отправка бинарника на устройство, пакетный менеджер, который установит программу. Потом она запустится, и ведь наверняка у ней есть некий этап инициализации (да хотя бы логин в твиттер или что там у них). Полминуты? Да, что-то вроде того. Купите кресло и мешок кофе.

Второй безальтернативный вариант - реальное устройство. Девайс лучше брать мощный. А лучше пять, разной степени говнистости, но один мощный. У меня их 4, 2 из них (худший и лучший) - постоянно со мной, 2 лежат в офисе на случай, если команде срочно потребуется альтернативный девайс для тестов. У моего коллеги 2 (ну и он всегда может взять с моего стола те 2 которые я не ношу с собой). Вы подумали только что, что мы все совсем тут еб^W с ума сошли? Нет, отнюдь. Например для тестирования iOS приложений у меня ровно 1 девайс. Просто это единственный способ бороться с другой проблемой платформы Android - "фрагментацией". Про это я могу под пиво задвинуть немалую тираду, но постараюсь тут и кратко.

О, все так полюбили это слово с подачи Джобса, но никто нихрена не понимает, что это значит по отношению к Андроиду. И Макс тоже не догоняет, считая эту проблему надуманной. Вот он рассказывает про адаптацию интерфейса, тут же признаваясь, что с офигенной системой менеджеров размещения Андроида это вообще не проблема для таких приложений как твиттер-клиент (но в то же время я с ужасом жду момента, когда придётся переносить с iOS приложение не использующее стандартный UI, для которого эта система будет бессмысленна). Да не в этом дело, при чём тут разные экраны и разрешения? Ребята из Google тут всё сделали за вас (против ребят из Apple, у которых например функция загрузки изображения соответствующего разрешения вообще не работает, хотя описана в документации). А дело в том, что Андроид есть только один - в git репозитариях Google и на Nexus One. Всё остальное - это прошивка от HTC, прошивка от LG, прошивка от Motorola, взгромождённые на железо от HTC, LG и Motorola соотв. И в эту прошивку, что характерно, этот производитель залез руками (да, чтобы был хоть какой-то added value, который выделял бы его телефончик на фоне сотен других моделей) и, вероятно, непоправимо там наследил. Один из телефонов, к примеру, появился у нас вследствие того, что производитель переписал стандартный класс из Android SDK так, что при его использовании приложение гарантированно падало с исключением. Пришлось брать этот класс из исходников андроида и адаптировать, заменяя своим вариантом как сломанный вариант у того производителя так и стандартный вариант у всех других и лишаясь потенциальных будущих его обновлений. Другой телефон гарантированно уходил в ребут в одном месте приложения. Без какой-либо причины, которую хоть как-то можно было бы установить. После пришедшего обновления перестал. Зато вдруг стал разряжаться за полдня даже в режиме ожидания. Вот что такое фрагментация Андроида - никогда невозможно гарантировать, что у пользователя будет хоть что-то работать. Будет работать у меня на 4 аппаратах, ещё на 2 у коллеги, на 2 у шефа - не будет у 100500 пользователей на каком-нибудь китайском куске говна. Кто-то из них непременно придёт в маркет и насрёт в карму. Видели наверное - у приложения >250 000 загрузок, 5 звёзд и куча истеричных комментариев. Энди Рубин даёт нам определение открытости как возможность собрать андроид и поставить на свой телефон целиком из исходников, я смеюсь над ним - пусть проделает этот трюк с произвольным телефоном из магазина. Или это должен сделать разработчик, который лишь хочет продать свою программу?

Железо разное, очень разное. Казалось бы, везде какой-то ARM, но один аппарат тормозит как тот эмулятор, а другой, раза в 2 дешевле с резистивным говно-экраном на 16 цветов - летает. Парадокс! Или вы думаете, что Rovio от хорошей жизни объявили, что их злые птицы не поддерживаются на куче устройств? Посмотрите на список - это устройства дешевле $500 (в России, очень грубая прикидка на глаз). Такие вот кирпичи. В кирпичи превращаются устройства, как только вы их купите. Они морально устарели, когда добрались до России, и производитель не будет выпускать для них новую прошивку. Купить что-то стоящее на Андроид - сложно, обычно это означает накинуть $50-$150 сверх того, что задумывалось, тщательно выбрать производителя по отзывам (и вероятности обновления прошивок), и магазин, в который можно без проблем вернуть устройство (или поменять). Но это так, к слову, потребительская сторона вопроса меня не особо касается, просто хочется подчеркнуть, что придётся тщательно выбирать. В случае с Apple придётся выбирать между 16 & 32 Gb к примеру, и только. И я не знаю, что лучше или хуже, но париться по поводу 16 и 32 обычно придётся гораздо меньше, чем с тысячей аспектов андроид телефона.

Что-то я отклонился. Далее Макс говорит о жизненном цикле приложения. И вот тут происходит очередной разрыв шаблона, потому что приложение на Android работает совсем по-другому, нежели привычное десктоп или даже iOS приложение. Как вам, например, тот факт, что приложение нельзя закрыть? Это не нужно в той парадигме, которую предлагает Google. Приложение, будучи запущенным, вероятно понадобится пользователю в дальнейшем. Ну так и не надо его закрывать, пусть оно будет доступно как можно быстрее, когда вы захотите к нему вернуться! А андроид сам позаботится об использовании памяти, процессора и батареи. Но это же просто невозможно! и пользователь требует кнопку "Закрыть". А единственный способ приложению закрыться - это послать себе kill -9, да и это не гарантирует, что удивлённый таким ходом событий андроид не перезапустит его тотчас же. Другие способы уже требуют пользователя - удалить приложение или перезагрузить телефон. Вот тогда оно точно закроется. Знаете, я видел одно приложение, которое предлагало себя закрыть. Как вы думаете, что оно делало? Скрывало все свои 'окна' и засыпало, как любое другое добропорядочное андроид приложение.

Тут разрыв шаблона случается и у разработчиков (у некоторой части), потому что чтобы стать "good citizen" нужно хотя бы пару раз хорошенько прочитать документацию по теме (по этой теме она весьма подробна) и приложить голову. И если хороший разработчик "в итоге будет писать гораздо более надёжные приложения, чем раньше (особенно после отладки)", то остальные "говнякают код по-быстрому", чтобы завалить маркет бесплатными поделиями. И это тоже большая, просто огромная проблема - отсутствие не только контроля, но и каких бы то ни было гайдлайнов - как для разработчиков софта, так и для производителей аппаратов. Поэтому в маркете такое количество шлака, о чём так любят упоминать противники платформы, забывая при этом, сколько шлака в Apple AppStore, а на прилавках такое количество неудобных аппаратов, то не имеющих D-pad в каком-либо виде, то с самой часто используемой на андроиде кнопкой "назад", засунутой в самое труднодоступное место, то страдающих чем-то ещё из широкого арсенала недоработок юзабелистов. Отсюда возникает самый популярный класс программ на андроиде - тасккиллеры, и холиворы - нужны они или нет. Пока я увидел в такой свободе только один положительный момент - отсутствие задержки между публикацией и доступностью приложения, за что все яростно клянут AppStore (упущенные возможности, конкуренты догоняют и пр.).

Далее идёт речь о самом SDK. Документация местами хороша, местами просто отсутствует, средства странны, не образуют что-то цельное и удобное (даже если заменить Eclipse на Idea, хоть последняя мне лично гораздо приятнее) и также неполны (ну какой смысл в отслеживании выделений памяти в куче, если большая её часть выделяется вне её и не отображается стандартными средствами? Собственные велосипеды дают лишь примерную картину) что в купе с драконовскими ограничениями типа слабых устройств на рынке, непредсказуемостью GC и домокловым мечом OutOfMemory (16 Mb! 21 век на дворе! и из этого треть откусывает runtime) создаёт картину безысходности. Нет, бывают вещи гораздо, гораздо хуже (RIM, вам икается?), но тут действительно непаханое поле для улучшений.

Такую же безрадостную картину может составить себе читатель статьи Android vs. iPhone: the good, the bad and the ugly нашего соотечественника Олега Андреева, но с ней я не во всём согласен, большей частью она была вызвана плохим аппаратом и непониманием. Согласен с тем, что делать вещи на Java гораздо сложнее, и только упрощением сборки мусора (которая только добавляет проблем на самом-то деле) нельзя это оправдать. Java даёт средства для постройки чего угодно, но даже простые вещи делаются сложно, и без хорошего опыта это ещё сложнее. Поэтому, например, перед началом изучения андроида я настоятельно порекомендую Java Concurrency in Practice. Это достаточно подробная, толстая и дорогая книга про многопоточность в Java. Это почти обязательно для разработки приложения сложнее фоточки кота и мяукания (это шпилька в адрес App Inventor. Где он кстати?).

Вопреки всему вышеизлитому яду я, как и Макс, считаю, что у Андроида всё впереди. Но для этого придётся пойти на решительнейшие шаги. Отказаться от любой поддержки старых прошивок (например ниже 2.1), остальные объявить устаревающими (deprecated) и только после этого выпускать следующую версию, подняв аппаратные требования, чтобы убрать наконец те ограничения, в которых вынуждена запускаться андроид программа. Это оставит на обочине большую часть ныне существующих аппаратов, но иначе детские болезни погубят платформу. Необходима работа над документацией (к примеру, в документации Microsoft встречаются недостаточно полно освещённые моменты, в документации Apple их меньше, в документации Google же зияют дыры); над гайдлайнами, в первую очередь HIG; средствами разработки, мониторинга и отладки; возможно даже над какой-либо системой принятия приложения в магазин.

Хороших выходных. Ответные посты коллег, подкреплённые опытом, приветствуются.

18 ноября 2010

немного стиля Android виджетам!

Вчера коллега спросил, как бы поменять "эти ужасные зелёные ползунки у SeekBar'а в оболочке HTC Sense"? Сегодня я над этим немного поразмыслил, благо недавно как раз заглядывал в эту тему.
Начать, пожалуй, стоит с ознакомления со стилями Android'а. Увы, в редкой книге поднимается эта тема, так что можно почитать про стили в документации и обратить внимание на встроенные стили. Во встроенных есть, например, такой фрагмент:

<style name="Widget.SeekBar">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">@android:drawable/progress_horizontal</item>
<item name="android:indeterminateDrawable">@android:drawable/progress_horizontal</item>
<item name="android:minHeight">20dip</item>
<item name="android:maxHeight">20dip</item>
<item name="android:thumb">@android:drawable/seek_thumb</item>
<item name="android:thumbOffset">8px</item>
<item name="android:focusable">true</item>
</style>

В нём и задаётся стиль для SeekBar'а. Значит, точно так же мы можем его переопределить. Как показывает вскрытие, @android:drawable/progress_horizontal есть фигура, описанная в xml (исходник, за ленью, выковыривать не стал), сделаем свою:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="1px" android:color="#FFF" />
<corners android:radius="9dip"/>

<gradient
android:angle="270"
android:endColor="#CCE2001A"
android:startColor="#CCA10013"
android:type="linear"/>
</shape>

Красный градиент в белой рамке.
Создадим стиль для виджета:
    <style name="MySeekBar">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">@drawable/seekbar</item>
<item name="android:indeterminateDrawable">@drawable/seekbar</item>
<item name="android:minHeight">20dip</item>
<item name="android:maxHeight">20dip</item>
<item name="android:thumbOffset">8px</item>
<item name="android:focusable">true</item>
</style>

и применим его на живом экземпляре:
<SeekBar
style="@style/MySeekBar"
android:id="@+id/screenControlVolume"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:layout_marginBottom="10dip"/>

Итог мучений (внизу - стандартный, не HTC):

Ну и, надо полагать, очевидно, что можно расширить и углубить мысль и применять этот подход почти ко всему.
UPD:
Как говорил мой завкафедры, показывая пальцем на голову, "Вы никогда не сможете перестать работать". И уже улёгшись спать, я вспомнил, что полоска-то в моём SeekBar'е одинакового цвета что слева от указателя позиции, что справа. Непорядок, который я сегодня исправляю. Итак, всё-таки расковыряв исходник android-варианта фигуры этой полоски, переписал свою версию:
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<stroke android:width="1px" android:color="@color/widgetBorder" />
<corners android:radius="9dip"/>

<gradient
android:angle="270"
android:endColor="@color/widgetBorder"
android:startColor="@color/widgetBorder"
android:type="linear"/>
</shape>
</item>

<item android:id="@android:id/progress">
<clip>
<shape>
<stroke android:width="1px" android:color="@color/widgetBorder" />
<corners android:radius="9dip"/>

<gradient
android:angle="270"
android:endColor="@color/gradientWidgetEndColor"
android:startColor="@color/gradientWidgetStartColor"
android:type="linear"/>
</shape>
</clip>
</item>
</layer-list>

тут уже список слоёв с 2 (в оригинале 3, зачем третья можете подумать на досуге), в которых могут быть разные фигуры, в моём случае - всё те же скруглённые градиентные прямоугольники, верхний слой обрезан - это левая часть. Ну и вот как это выглядит в моём проекте:

14 ноября 2010

Ну и опять про браузеры. И андроид.

Просто для поднятия настроения, раз уж я тут картинки разбираю. Документация Google Android в Google Chrome и Opera (версии последниие). И не говорите мне после этого ничего, и не осуждайте выбор. На самом android'е, кстати, встроенный браузер тоже слажал немного, не показав нижнюю левую панель, Opera Mobile справилась (хотя и были неточности).

13 ноября 2010

Gradients in Android

Построение интерфейса Android'а через xml - это сплошные преимущества, куда не посмотри. Только привыкнуть и научиться надо (конечно, на это надо время, которого никогда нет, поэтому этот рабочий пост написан в выходной).

Вот пример - описав на xml радиальный градиент, используемый в качестве фона приложения, сократил размер выходного пакета почти в 3 раза за счёт того, что выкинул картинки с фоном. Осталось только с дизайнером сесть и цвета поправить.

Ну и чтоб два раза не вставать, вот так можно ескейпить код в HTML:
alias -g E='| ruby -rcgi -e "ARGF.each{|line| puts CGI.escapeHTML line}"'
это на zsh.

XML:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:centerX="0.5"
android:centerY="0.5"
android:endColor="#023F8F"
android:gradientRadius="300"
android:startColor="#1A96CA"
android:type="radial"
/>
</shape>


До и после: