JustPaste.it

Хакер - Минутка ненависти Android-разработчика. Разбираем 10 самых частых проблем кодинга

https://t.me/hacker_frei

Содержание статьи

Двадцать лет назад использовать Android было невозможно. Десять лет назад было еще рано. Сегодня — уже поздно. Конечно, я утрирую, но, когда операционная система молода, многие ее недостатки можно списать на «детские болезни». Их можно понять, простить и не замечать, ожидая скорейших багфиксов от компании-производителя, но… Android уже дорос, пожалуй, до бальзаковского возраста, а мы все так же решаем проблемы, которые давным-давно должны быть исправлены. Сегодня мы рассмотрим те затруднения при разработке под Android, с которыми ты точно когда-нибудь столкнешься. И которые, кстати, дико бесят. 

 

Жизненный цикл Activity может в любой момент перечеркнуть все твои планы

Если ты программируешь под Android, то наверняка видел схему жизненного цикла для самой простой активити. А знал ли ты жизненный цикл окошка с кнопочками, которое создавал компилятор старого и доброго Delphi? Я думаю — нет, не знал, и знать тебе это было не нужно. Интересно, как бы на тебя посмотрели олдскульные дельфисты-паскалисты, если бы ты им сказал: «когда пользователь перевернет свой экран, нам надо пересоздать все формы и восстановить состояние всех компонентов». Скорее всего, они бы пальцем у виска покрутили. И не только потому, что переворачивать старые мониторы и системные блоки было не принято. 

А меж тем Android именно так и устроен: повернул экран — начинай все сначала. Конечно, в настройках ты можешь отключить поворот экрана, но это не всегда удобно, да и рядовые пользователи не знают и десяти процентов возможностей своего смартфона. Поэтому сейчас имеем мы то, что имеем, и единственное, что ты можешь сделать при разработке, — это отключить в манифесте пересоздание Activity, добавив свойства

 

android:configChanges="keyboardHidden|orientation|screenSize"

Конечно, «знающие люди» так делать не рекомендуют, но такой костыль используют даже серьезные социальные приложения. Если не веришь — посмотри сам манифесты из их APK (вот инструкция).

Дело осложняют и сами производители устройств — каждый из них адаптирует ОС к своим устройствам, меняя в том числе ее поведение. Например, традиционно рекомендуется сохранять данные при событии onStop. Пользователь свернул приложение, и вызвался этот метод. Но есть одна проблема: на некоторых устройствах вызов этого метода не гарантирован. В таком случае нужно сохранять все, что можешь, в методе onPause. Правда, он вызывается не только при выходе из активити, но и при показе диалогового окна, поэтому нужно предвидеть этот момент и предусматривать проверки на показ диалога.

Какой известный лончер для Android сейчас старательно хоронит его производитель?

  • Google Now Launcher
  • Google Pixel Launcher
  • Microsoft Launcher
 

Сбор ошибок, которого не было

Я с тоской вспоминаю старые времена виндовой разработки. Кому нужны системы для сбора ошибок? Да никому! Большинство ошибок лежало «на поверхности», программа или работает, или нет. Если она периодически вылетает — значит, «проклятая винда опять глючит». 

А если она вылетает по вине программиста, то и не страшно, ведь онлайн-сторы программного обеспечения еще не придумали и никто не засыплет твою программу минусами и гневными комментариями. Максимум — под пивко поплачет в жилетку своему дилеру пиратского ПО на Митинском радиорынке.

Сегодня ты лично, оперативно и максимально прозрачно отвечаешь за каждый свой 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.

Дерево зависимостей Дерево зависимостей

Для удаления хотя бы части ненужного кода можно прописать правило для 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.

Ты уже писал приложения для Android?

  • Да, и спасибо автору за подсказки
  • Нет, и теперь совсем расхотелось пробовать
  • Слепил APK в конструкторе приложений, и оно даже как-то работает
 

Просто записать файл на флешку не получится: спроси разрешения, а лучше городи контент-провайдер

Сама идея ограничивать доступ программ к файловой системе — благая и по сравнению с «виндовой вольницей», где каждый делает что хочет, конечно, секьюрная. Но какой же это геморрой, коллеги!

Перекинуть данные через простой файл не разрешает сама ОС. Хочешь обмена? Пиши контент-провайдер. Точно нужно записать что-нибудь на диск? Реально нужно? Изволь спросить у пользователя кучу разрешений и заранее продумать, что делать, если он их тебе не даст.

 

Все стандартные медиакомпоненты просто ужасны

Максимум, на что способны классы VideoView, MediaPlayer и SurfaceView, — заставить тебя чесать репу и просиживать долгие часы за компьютером. Если тебе нужен результат, то ищи сторонние библиотеки. Пусть чужой опыт сэкономит тебе время и нервы. Вот хороший плеер.

Для работы с камерой изучи «Побеждаем Android Camera2 API с помощью RxJava2».

Как лучше проигрывать музыку? Подсмотри у Timber и Phonograph.

 

Любой желающий может декомпилировать твое приложение и изменить его, как захочет, — оно просто создано для этого

Исторически сложилось так (и это уже точно не исправить), что код для Android работает в виртуальной машине. Кому пришло в голову поднимать на низкопроизводительных ARM-процессорах виртуалки? Вряд ли теперь мы это узнаем. Apple сделала все, как надо, и завоевала приз наших зрительских симпатий, а вот «корпорация добра» решила извратиться, и теперь нас напрягает (спасибо современным процессорам) даже не производительность, а тот факт, что исходный код приложения можно восстановить почти что до запятой.

Пиши свой код качественнее, и его будут читать не только китайские хакеры, но и программисты из развитых стран — считай это успехом. А стоит тебе пренебречь обфускацией, и любой школьник сможет модифицировать твою программу и сделать на ее основе свой шедевр.

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei