Содержание статьи
- Жизненный цикл Activity может в любой момент перечеркнуть все твои планы
- Сбор ошибок, которого не было
- Теперь я стреляю у девушек телефон... чтобы отловить на нем баги
- Хочешь меньше багов в приложении? Выкидывай фрагменты и асинктаски (лоадеры тоже не забудь)
- Фрагментация ухудшает внешний вид
- Библиотекам поддержки самим нужна «помощь и поддержка»
- «Мы хотели помочь вам c разметкой и написали Constraint Layout, но он падает и тормозит»
- Просто записать файл на флешку не получится: спроси разрешения, а лучше городи контент-провайдер
- Все стандартные медиакомпоненты просто ужасны
- Любой желающий может декомпилировать твое приложение и изменить его, как захочет, — оно просто создано для этого
Жизненный цикл Activity может в любой момент перечеркнуть все твои планы
Если ты программируешь под Android, то наверняка видел схему жизненного цикла для самой простой активити. А знал ли ты жизненный цикл окошка с кнопочками, которое создавал компилятор старого и доброго Delphi? Я думаю — нет, не знал, и знать тебе это было не нужно. Интересно, как бы на тебя посмотрели олдскульные дельфисты-паскалисты, если бы ты им сказал: «когда пользователь перевернет свой экран, нам надо пересоздать все формы и восстановить состояние всех компонентов». Скорее всего, они бы пальцем у виска покрутили. И не только потому, что переворачивать старые мониторы и системные блоки было не принято. 🙂
А меж тем Android именно так и устроен: повернул экран — начинай все сначала. Конечно, в настройках ты можешь отключить поворот экрана, но это не всегда удобно, да и рядовые пользователи не знают и десяти процентов возможностей своего смартфона. Поэтому сейчас имеем мы то, что имеем, и единственное, что ты можешь сделать при разработке, — это отключить в манифесте пересоздание Activity, добавив свойства
android:configChanges="keyboardHidden|orientation|screenSize"
Конечно, «знающие люди» так делать не рекомендуют, но такой костыль используют даже серьезные социальные приложения. Если не веришь — посмотри сам манифесты из их APK (вот инструкция).
Дело осложняют и сами производители устройств — каждый из них адаптирует ОС к своим устройствам, меняя в том числе ее поведение. Например, традиционно рекомендуется сохранять данные при событии onStop
. Пользователь свернул приложение, и вызвался этот метод. Но есть одна проблема: на некоторых устройствах вызов этого метода не гарантирован. В таком случае нужно сохранять все, что можешь, в методе onPause
. Правда, он вызывается не только при выходе из активити, но и при показе диалогового окна, поэтому нужно предвидеть этот момент и предусматривать проверки на показ диалога.
Сбор ошибок, которого не было
Я с тоской вспоминаю старые времена виндовой разработки. Кому нужны системы для сбора ошибок? Да никому! Большинство ошибок лежало «на поверхности», программа или работает, или нет. Если она периодически вылетает — значит, «проклятая винда опять глючит». 🙂 А если она вылетает по вине программиста, то и не страшно, ведь онлайн-сторы программного обеспечения еще не придумали и никто не засыплет твою программу минусами и гневными комментариями. Максимум — под пивко поплачет в жилетку своему дилеру пиратского ПО на Митинском радиорынке.
Сегодня ты лично, оперативно и максимально прозрачно отвечаешь за каждый свой begin и end в Kotlin-коде. Поэтому собирать ошибки нужно сразу при старте приложения.
Систем сбора сейчас расплодилось превеликое множество, но лично я пользуюсь Crashlytics. В ее пользу говорит и то, что ее недавно купила сама Google. Включать сбор ошибок можно для каждой активити отдельно, но проще сразу включить его в классе Application:
@Override
protected void onCreate() {
super.onCreate(savedInstanceState);
Fabric.with(this, new Crashlytics());
try {
FirebaseApp.initializeApp(this);
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
Crashlytics.log(Log.INFO, "App.onCreate", "Firebase initialized");
} catch (Exception e) {
e.printStackTrace();
Crashlytics.log(Log.ERROR, "App.onCreate",
"Error initialize Firebase with: " + e.getMessage());
}
}
Выполнение кода в этом месте может затянуть показ первого экрана приложения, но туда можно через тему поставить свой Splash и убить сразу двух зайцев — подгрузишь инструменты и развлечешь пользователя.
Как видно из приведенного выше кода, один инструмент Google — Crashlytics — следит за работой другого — Firebase. Несмотря на то что оба они могут выполнять одинаковые задачи — собирать события, Crashlytics действует так:
Crashlytics.log(Log.INFO, "App.onCreate", "Firebase initialized");
А Firebase — вот так:
public static void selectContent(String type, String id) {
if (mFirebaseAnalytics != null) {
Bundle bundle = new Bundle();
bundle.putString(FirebaseAnalytics.Param.ITEM_ID, id);
bundle.putString(FirebaseAnalytics.Param.CONTENT_TYPE, type);
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_CONTENT, bundle);
}
}
Теперь я стреляю у девушек телефон... чтобы отловить на нем баги
Про изменение прошивки производителем ты уже слышал. Но как быть, если неприятность уже случилась и твое приложение, к примеру, стабильно падает у производителя X на устройстве Y с прошивкой Z?
Все бы ничего — подумаешь, одно падение у одного устройства. Но таких устройств было продано несколько миллионов штук, так что гневных отзывов и однозвездных комментариев тебя ждет несколько десятков. Как быть? Использовать фермы для тестирования. Наш материал про семь лучших ферм все еще актуален, советую его прочитать.
Из халявных инструментов я бы предпочел Firebase, который на бесплатном тарифе дает прогнать тесты по десяти реальным устройствам. Кроме того, не забывай погуглить собственные веселые фермы от разработчиков смартфонов. И заводи контакты с людьми, которые работают в магазинах электроники или сервисных центрах (особенно неплохо это получается в маленьких городах). Тогда ты сможешь делать, как я, — брать устройства для тестов у них. Главное, не забудь вернуть гаджет в первоначальное состояние и скрой меню для разработчиков, если оно было заблокировано ранее.
Хочешь меньше багов в приложении? Выкидывай фрагменты и асинктаски (лоадеры тоже не забудь)
Говорят, что секрет 99,9% удачных пусков приложения — в отказе от фрагментов в любом виде. Дело в том, что у разных производителей они порой выкидывают такие замысловатые ошибки, что понять их можно только с помощью хрустального шара. Если шаром ты владеть не обучен, лучше вовсе откажись от фрагментов. Тот же ViewPager можно сделать и без них.
Асинктаски можно использовать для разовых фоновых запросов, но, если нужно много работы делать в фоне, используй другие инструменты (Rx, сервисы). Ну а лоадеры имеют старый баг, связанный с тем, что колбэки о завершении могут вообще не вызываться. Говорят, что в новых версиях это исправили, но проверять я бы не стал (они так каждые полгода говорят).
Фрагментация ухудшает внешний вид
Огромный парк разноформатных устройств — одновременно баг и фича мира Андроида. Из-за большой фрагментации приходится вымерять разметку под каждую плотность экрана. Редактор макетов экранов при этом крайне неудобный. Из-за этого особо отчаянные (Telegram) вообще его не используют, а генерируют экраны динамически, из кода.
А как там с редизайном стандартных меню и вкладок? Легко! Два дня вдумчивого гугления, ящик пива, блок сигарет, пробы, ошибки, несколько костылей — и пожалуйста, приложение выглядит почти как нарисовал дизайнер. 🙂 Уверен, что «отличные» компоненты DrawerLayout
и ViewPager
отлично научат тебя пользоваться поиском при любом нестандартном поведении или когда просто захочешь сменить шрифты в меню.
Библиотекам поддержки самим нужна «помощь и поддержка»
Серьезно, каждый новый релиз — новые костыли! Почти все компоненты из библиотеки поддержки несут неизлечимые баги, которые не исправляются годами. У меня было несколько ошибок, которые умерли вместе с устройствами, но так и не были исправлены. К примеру, отличный класс для уведомлений NotificationCompat
меняется каждую версию Android, и ты меняешь свой код вслед за ней.
Библиотеки поддержки очень большие и сами тянут в проект библиотеки для поддержки. Программисты даже шутят: «Каждый класс в этих библиотеках будет иметь суффикс CompatCompat». Кстати, чтобы увидеть, что тянет та или иная библиотека за собой, можно воспользоваться инструментом gradle — dependencies.
Xakep #230. Социальная инженерия
Для удаления хотя бы части ненужного кода можно прописать правило для gradle:
configurations.all {
exclude group : 'com.android.support', module :'transition'
exclude group : 'com.android.support', module :'customtabs'
exclude group : 'com.android.support', module :'support-media-compat'
exclude group : 'com.android.support', module :'support-fragment'
}
После отработки правил исключения не забудь еще раз все протестировать.
«Мы хотели помочь вам c разметкой и написали Constraint Layout, но он падает и тормозит»
Новинка, которая должна была упростить нам жизнь, — Constraint Layout — сложна в использовании, и приложение из-за нее становится тяжелее и медленнее. Чтобы работать с этим инструментом эффективнее, советую прочесть статью. А в преддверии версии Constraint Layout 2.0 можно изучить это выступление. По слухам, его представят на Google IO 2018.
Просто записать файл на флешку не получится: спроси разрешения, а лучше городи контент-провайдер
Сама идея ограничивать доступ программ к файловой системе — благая и по сравнению с «виндовой вольницей», где каждый делает что хочет, конечно, секьюрная. Но какой же это геморрой, коллеги!
Перекинуть данные через простой файл не разрешает сама ОС. Хочешь обмена? Пиши контент-провайдер. Точно нужно записать что-нибудь на диск? Реально нужно? Изволь спросить у пользователя кучу разрешений и заранее продумать, что делать, если он их тебе не даст.
Все стандартные медиакомпоненты просто ужасны
Максимум, на что способны классы VideoView
, MediaPlayer
и SurfaceView
, — заставить тебя чесать репу и просиживать долгие часы за компьютером. Если тебе нужен результат, то ищи сторонние библиотеки. Пусть чужой опыт сэкономит тебе время и нервы. Вот хороший плеер.
Для работы с камерой изучи «Побеждаем Android Camera2 API с помощью RxJava2».
Как лучше проигрывать музыку? Подсмотри у Timber и Phonograph.
Любой желающий может декомпилировать твое приложение и изменить его, как захочет, — оно просто создано для этого
Исторически сложилось так (и это уже точно не исправить), что код для Android работает в виртуальной машине. Кому пришло в голову поднимать на низкопроизводительных ARM-процессорах виртуалки? Вряд ли теперь мы это узнаем. Apple сделала все, как надо, и завоевала приз наших зрительских симпатий, а вот «корпорация добра» решила извратиться, и теперь нас напрягает (спасибо современным процессорам) даже не производительность, а тот факт, что исходный код приложения можно восстановить почти что до запятой.
Пиши свой код качественнее, и его будут читать не только китайские хакеры, но и программисты из развитых стран — считай это успехом. 😉 А стоит тебе пренебречь обфускацией, и любой школьник сможет модифицировать твою программу и сделать на ее основе свой шедевр.