Даже если ваше приложение быстрое и отзывчивое, некоторые дизайнерские решения все равно могут вызвать проблемы у пользователей — из-за незапланированных взаимодействий с другими приложениями или диалоговыми окнами, непреднамеренной потери данных, непреднамеренной блокировки и т. д. Чтобы избежать этих проблем, полезно понять контекст, в котором работают ваши приложения, и системные взаимодействия, которые могут повлиять на ваше приложение. Короче говоря, вам следует стремиться разработать приложение, которое беспрепятственно взаимодействует с системой и другими приложениями.
Распространенной проблемой бесшовности является ситуация, когда фоновый процесс приложения — например, служба или приемник широковещательных сообщений — открывает диалоговое окно в ответ на какое-то событие. Это может показаться безобидным поведением, особенно когда вы создаете и тестируете приложение изолированно, на эмуляторе. Однако когда ваше приложение запускается на реальном устройстве, ваше приложение может не иметь фокуса пользователя в тот момент, когда фоновый процесс отображает диалоговое окно. Таким образом, может случиться так, что ваше приложение будет отображать свое диалоговое окно позади активного приложения или оно может переключить фокус с текущего приложения и отображать диалоговое окно перед тем, что делает пользователь (например, при наборе телефонного звонка). Такое поведение не будет работать ни для вашего приложения, ни для пользователя.
Чтобы избежать этих проблем, ваше приложение должно использовать соответствующие системные средства для уведомления пользователя — классы Notification
. Используя уведомления, ваше приложение может сигнализировать пользователю о том, что событие произошло, отображая значок в строке состояния, а не отвлекая внимание и прерывая пользователя.
Другой пример проблемы бесшовности — когда действие случайно теряет данные о состоянии или пользователя из-за неправильной реализации onPause() и других методов жизненного цикла. Или, если ваше приложение предоставляет данные, предназначенные для использования другими приложениями, вам следует предоставлять их через ContentProvider, а не (например) делать это через общедоступный необработанный файл или базу данных.
Общим для этих примеров является то, что они предполагают хорошее взаимодействие с системой и другими приложениями. Система Android спроектирована таким образом, чтобы рассматривать приложения как своего рода объединение слабосвязанных компонентов, а не как куски кода «черного ящика». Это позволяет вам, как разработчику, рассматривать всю систему как еще большую совокупность этих компонентов. Это принесет вам пользу, поскольку позволит вам аккуратно и плавно интегрироваться с другими приложениями, поэтому вам следует разработать собственный код, чтобы отплатить тем же.
В этом документе обсуждаются распространенные проблемы бесшовности и способы их предотвращения.
Не сбрасывайте данные
Всегда помните, что Android — это мобильная платформа. Это может показаться очевидным, но важно помнить, что другое действие (например, приложение «Входящий телефонный звонок») может появиться поверх вашего собственного действия в любой момент. Это приведет к срабатыванию методов onSaveInstanceState() и onPause() и, скорее всего, приведет к закрытию вашего приложения.
Если пользователь редактировал данные в вашем приложении, когда появилось другое действие, ваше приложение, скорее всего, потеряет эти данные, когда ваше приложение будет закрыто. Если, конечно, предварительно не сохранить незавершенную работу. «Путь Android» заключается именно в этом: приложения Android, которые принимают или редактируют входные данные, должны переопределять метод onSaveInstanceState() и сохранять свое состояние подходящим способом. Когда пользователь повторно посещает приложение, он должен иметь возможность получить свои данные.
Классическим примером хорошего использования такого поведения является почтовое приложение. Если пользователь писал электронное письмо во время запуска другого действия, приложение должно сохранить незавершенное электронное письмо как черновик.
Не раскрывайте необработанные данные
Если вы не пойдете по улице в нижнем белье, то и ваши данные тоже не будут этого делать. Несмотря на то, что некоторые виды приложений можно открыть для чтения всему миру, обычно это не лучшая идея. Для предоставления необработанных данных другие приложения должны понимать ваш формат данных; если вы измените этот формат, вы нарушите работу всех других приложений, которые не обновляются аналогичным образом.
«Путь Android» заключается в создании ContentProvider для предоставления ваших данных другим приложениям через чистый, продуманный и удобный в обслуживании API. Использование ContentProvider во многом похоже на вставку интерфейса языка Java для разделения и компонентизации двух тесно связанных фрагментов кода. Это означает, что вы сможете изменить внутренний формат ваших данных, не меняя интерфейс, предоставляемый ContentProvider, и это не затрагивает другие приложения.
Не перебивайте пользователя
Если пользователь запускает приложение (например, приложение «Телефон» во время разговора), можно с уверенностью сказать, что он сделал это намеренно. Вот почему вам следует избегать создания действий, за исключением прямого ответа на ввод пользователя из текущего действия.
То есть не вызывайте startActivity() из BroadcastReceivers или служб, работающих в фоновом режиме. Это приведет к прерыванию работы любого приложения, что приведет к раздражению пользователя. Возможно, что еще хуже, ваше действие может стать «бандитом нажатия клавиш» и получить часть входных данных, которые пользователь предоставлял предыдущему действию. В зависимости от того, что делает ваше приложение, это может быть плохой новостью.
Вместо создания пользовательских интерфейсов активности непосредственно из фона вам следует использовать NotificationManager для установки уведомлений. Они появятся в строке состояния, и пользователь сможет на досуге щелкнуть по ним, чтобы посмотреть, что ему может показать ваше приложение.
(Обратите внимание, что все это не относится к случаям, когда ваше собственное действие уже находится на переднем плане: в этом случае пользователь ожидает увидеть ваше следующее действие в ответ на ввод.)
Есть много дел? Сделайте это в теме
Если вашему приложению необходимо выполнить какие-то дорогостоящие или длительные вычисления, вам, вероятно, следует перенести его в поток. Это предотвратит отображение ужасного диалогового окна «Приложение не отвечает» пользователю, что в конечном итоге приведет к полному прекращению работы вашего приложения.
По умолчанию весь код в Activity, а также во всех его представлениях выполняется в одном потоке. Это тот же поток, который обрабатывает события пользовательского интерфейса. Например, когда пользователь нажимает клавишу, событие нажатия клавиши добавляется в очередь основного потока Activity. Система обработчика событий должна быстро исключить из очереди и обработать это событие; если этого не происходит, система через несколько секунд приходит к выводу, что приложение зависло, и предлагает пользователю закрыть его.
Если у вас есть долго выполняющийся код, его встроенный запуск в Activity запустит его в потоке обработчика событий, эффективно блокируя обработчик событий. Это задержит обработку ввода и приведет к появлению диалоговых окон ANR. Чтобы избежать этого, переместите ваши вычисления в поток. В этом документе «Дизайн для отзывчивости» обсуждается, как это сделать.
Не перегружайте ни один экран активности
Любое приложение, которое стоит использовать, вероятно, будет иметь несколько разных экранов. При разработке экранов вашего пользовательского интерфейса обязательно используйте несколько экземпляров объекта Activity.
В зависимости от вашего опыта разработки вы можете интерпретировать действие как нечто похожее на Java-апплет, поскольку оно является точкой входа для вашего приложения. Однако это не совсем точно: если подкласс Applet является единственной точкой входа для Java-апплета, Activity следует рассматривать как одну из потенциально нескольких точек входа в ваше приложение. Единственная разница между вашей «основной» активностью и любыми другими, которые у вас могут быть, заключается в том, что «основная» активность оказывается единственной, которая проявила интерес к действию «android.intent.action.MAIN» в вашем AndroidManifest. xml-файл.
Итак, при разработке приложения думайте о нем как о федерации объектов Activity. Это сделает ваш код более удобным в сопровождении в долгосрочной перспективе, а в качестве приятного побочного эффекта он также будет хорошо сочетаться с историей приложений Android и моделью «backstack».
Расширение системных тем
Когда дело доходит до внешнего вида пользовательского интерфейса, важно, чтобы он хорошо вписывался. Пользователей раздражают приложения, которые контрастируют с пользовательским интерфейсом, который они привыкли ожидать. При разработке пользовательских интерфейсов вам следует стараться максимально избегать развертывания собственных. Вместо этого используйте тему. Вы можете переопределить или расширить те части темы, которые вам нужны, но, по крайней мере, вы начинаете с той же базы пользовательского интерфейса, что и все другие приложения. Все подробности читайте в разделе «Стили и темы» .
Создайте свой пользовательский интерфейс для работы с несколькими разрешениями экрана.
Различные устройства на базе Android будут поддерживать разные разрешения экрана. Некоторые даже смогут менять разрешение на лету, например, переключаясь в альбомный режим. Важно убедиться, что ваши макеты и рисунки достаточно гибки, чтобы правильно отображаться на различных экранах устройств.
К счастью, это очень легко сделать. Короче говоря, вам нужно предоставить разные версии вашего изображения (если вы его используете) для ключевых разрешений, а затем разработать макет с учетом различных размеров. (Например, избегайте использования жестко запрограммированных позиций и вместо этого используйте относительные макеты.) Если вы сделаете это, система сделает все остальное, и ваше приложение будет отлично выглядеть на любом устройстве.
Предположим, сеть медленная
Устройства Android будут поставляться с различными вариантами сетевого подключения. Все они будут иметь определенные возможности доступа к данным, хотя некоторые из них будут работать быстрее, чем другие. Однако наименьшим общим знаменателем является GPRS, служба передачи данных, не относящаяся к 3G, для сетей GSM. Даже устройства с поддержкой 3G будут проводить много времени в сетях, отличных от 3G, поэтому медленные сети останутся реальностью еще довольно долгое время.
Вот почему вам всегда следует кодировать свои приложения, чтобы минимизировать доступ к сети и пропускную способность. Вы не можете рассчитывать на то, что сеть работает быстро, поэтому всегда следует планировать, что она будет медленной. Если ваши пользователи работают в более быстрых сетях, это здорово — их опыт только улучшится. Однако следует избегать обратного случая: приложения, которые какое-то время можно использовать, но в остальное время раздражающе замедляют работу в зависимости от того, где находится пользователь в любой момент времени, скорее всего, будут непопулярными.
Одна из потенциальных ошибок здесь заключается в том, что очень легко попасть в эту ловушку, если вы используете эмулятор, поскольку эмулятор использует сетевое соединение вашего настольного компьютера. Это почти гарантированно будет намного быстрее, чем сотовая сеть, поэтому вам нужно изменить настройки эмулятора, которые имитируют более медленные скорости сети. Вы можете сделать это в Android Studio через AVD Manager или с помощью параметра командной строки при запуске эмулятора.
Не думайте, что сенсорный экран или клавиатура
Android будет поддерживать различные форм-факторы телефонов. Это причудливый способ сказать, что некоторые устройства Android будут иметь полноценную QWERTY-клавиатуру, а другие будут иметь 40-клавишную, 12-клавишную или даже другие конфигурации клавиш. Аналогичным образом, некоторые устройства будут иметь сенсорные экраны, но многие — нет.
Помните об этом при создании приложений. Не делайте предположений относительно конкретных раскладок клавиатуры — если, конечно, вы действительно не заинтересованы в том, чтобы ограничить использование вашего приложения только на этих устройствах.
Берегите аккумулятор устройства
Мобильное устройство не очень мобильно, если оно постоянно подключено к розетке. Мобильные устройства питаются от аккумулятора, и чем дольше мы сможем продлить срок службы аккумулятора, тем счастливее будут все, особенно пользователь. Двумя крупнейшими потребителями энергии аккумулятора являются процессор и радио; вот почему важно писать приложения так, чтобы они выполняли как можно меньше работы и использовали сеть как можно реже.
Минимизация количества процессорного времени, используемого вашим приложением, на самом деле сводится к написанию эффективного кода . Чтобы свести к минимуму энергопотребление при использовании радиомодуля, обязательно корректно обрабатывайте ошибки и извлекайте только то, что вам нужно. Например, не повторяйте постоянно сетевую операцию, если она не удалась. Если однажды произошел сбой, то, скорее всего, у пользователя нет приема, поэтому, вероятно, произойдет сбой снова, если вы попытаетесь сразу же; все, что вы будете делать, это тратить заряд батареи.
Пользователи довольно умны: если ваша программа потребляет много энергии, вы можете рассчитывать на то, что они это заметят. Единственное, в чем вы можете быть уверены на этом этапе, это то, что ваша программа не будет оставаться установленной очень долго.