Каждое Android — приложение запускается в своем собственном процессе. Поэтому приложение изолировано от других запущенных приложений, и неправильно работающее приложение не может беспрепятственно навредить другим Android -приложениям.
Тем не менее, главным параметром Android -приложения является возможность использовать компоненты других приложений, если они дают на это соответствующие права . Допустим, нам нужен некий компонент с прокруткой для отображения текста, и похожий компонент уже реализован в другом приложении. Тогда у нас есть возможность использовать реализованный компонент . В этом случае наше приложение не копирует необходимый код к себе и не создает ссылку на него. Вместо этого приложение делает запрос на исполнение части кода другого приложения, где есть нужный нам компонент .
В Android существует четыре типа компонентов: Activities , Services , Broadcast receivers и Content providers .
Также важно отметить объекты Intents , в Android -приложениях почти все работает благодаря им. Intent – это механизм для описания одной операции (выбрать фотографию, отправить письмо , сделать звонок, запустить браузер и перейти по указанному адресу и другие). Наиболее распространенный сценарий использования Intent – запуск другого Activity в своем приложении.
Как устроен Android и его приложения.
1.6.1. Activities
Activity представляет собой пользовательский интерфейс для одного действия, которое пользователь может совершить. Например, приложение для обмена текстовыми сообщениями может иметь одно Activity для отображения списка контактов, другое – для написания сообщения выбранному контакту, третье – для просмотра сообщений и еще одно для изменения настроек. Все эти Activities формируют единый пользовательский интерфейс, но не зависят друг от друга.
Приложение может состоять из одного Activity или из нескольких. Это зависит от типа приложения и его дизайна. Одно Activity может вызвать другое. Каждое Activity задает окно для отображения, которое, обычно, занимает весь экран, но может быть меньше и плавать поверх других окон. Activity может использовать дополнительные окна, например, всплывающий диалог, который требует промежуточного ответа пользователя, или окно, которое отображает пользователям важную информацию при выборе элемента, заслуживающего особого внимания.
Визуальный интерфейс строится на основе иерархии визуальных компонентов, производных от базового класса View. Android имеет ряд готовых к использованию компонентов, а также кнопки, текстовые поля, полосы прокрутки, меню, флажки и многие другие.
Activity может находиться в одном из трех состояний:
- Active или Running – находится на переднем плане и имеет фокус для взаимодействия с пользователем.
- Paused – потеряло фокус, но все еще видно пользователю. Сверху находится другое Activity , которое или прозрачно или закрывает не весь экран. Приостановленное Activity полностью «живое» (его состояние сохранено), но может быть уничтожено системой в случае нехватки памяти.
- Stopped – полностью перекрыто другим Activity . Оно больше не видно пользователю и будет уничтожено системой, когда понадобится память.
Если Activity приостановлено или остановлено, система может удалить его из памяти, либо послать запрос на его завершение, или просто уничтожить его процесс. Когда Activity снова отображается пользователю, его состояние полностью восстанавливается.
ЧТО ВНУТРИ ПРИЛОЖЕНИЯ? РАЗБОР
Переходя от состояния к состоянию, Activity уведомляет об этом, вызывая следующие методы:
- void onCreate()
- void onStart()
- void onRestart()
- void onResume()
- void onPause()
- void onStop()
- void onDestroy()
Жизненный цикл Activity состоит из трех вложенных циклов (Рис. 1.3):
- Жизненный цикл activity начинается с вызова метода onCreate() , в котором производится первоначальная настройка глобального состояния, и завершается вызовом метода onDestroy() , в котором оно освобождает занятые ресурсы.
- Видимая часть жизненного цикла происходит между вызовами onStart() и onStop() . В течение этого времени пользователь может видеть Activity на экране, хотя оно может быть не на переднем плане и не взаимодействовать с пользователем. Методы onStart() и onStop() могут вызываться столько раз, сколько Activity становится видимым или скрытым для пользователя.
- На переднем плане Activity находится между вызовами onResume() и onPause() . В течение этого времени Activity находится поверх других и взаимодействует с пользователем. Activity может часто переходить в состояние паузы и выходить из него. Например, метод onPause() может быть вызван, когда устройство переходит в спящий режим или когда запускается другое Activity , а метод onResume() – при получении результата от закрывающегося Activity .
Рис. 1.3. Жизненный цикл Activity
Следующая таблица более детально описывает каждый из уже перечисленных методов и его место в жизненном цикле Activity .
За ним всегда следует вызов метода onStart() .
За ним всегда следует вызов onResume()
За ним следует вызов onResume() , если Activity переходит на передний план, или onStop() , если оно скрывается.
За ним следует вызов onPause() .
За ним может быть вызван метод onResume() если Activity возвращается на передний план, или метод onStop() , если оно становится невидимым для пользователя.
Затем может быть вызван либо метод onRestart() , если Activity возвращается для взаимодействия с пользователем, либо метод onDestroy() , если оно завершается.
Обратите внимание на колонку «Может ли быть уничтожен?». Она указывает на то, может ли система уничтожить процесс, в котором запущено Activity , в любой момент после возврата из этого метода, не выполняя больше ни одной строчки кода Activity . Три метода: OnPause(), OnStop() и OnDestroy() – отмечены «Да». Но только метод OnPause() будет гарантированно вызван перед уничтожением процесса, поскольку он первый в этом списке, а OnStop() и OnDestroy() могут не вызываться. Поэтому для сохранения измененных данных нужно использовать метод OnPause() . Методы, отмеченные «Нет», защищают процесс, в котором запущено Activity, от уничтожения с момента их вызова.
1.6.2. Типы процессов в Android-приложении
Жизненный цикл приложения тесно связан с жизненным циклом его процесса. Также он зависит от текущего состояния системы. В случае нехватки памяти, Android убивает наименее значимые процессы. Значимость процесса зависит от его типа. Типы процессов, в зависимости от важности, выглядят следующим образом (от наиболее до наименее важных):
- Процесс переднего плана – процесс приложения, с которым пользователь взаимодействует в данный момент. Процесс считается таковым, если его Activity находится на вершине Activity-стека (была вызвана функция onResume() , или его Broadcast Receiver работает в настоящее время (в данный момент исполняется приложением onReceive()) , или же его Service выполняет callback-методы, такие как onCreate() , onStart() или onDestroy() . Как правило, таких процессов очень мало и они закрываются в самую последнюю очередь.
- Видимый процесс — процесс, который имеет Activity, видимый конечному пользователю в данный момент времени. Процессов, которые выводятся на экран, очень мало, поэтому их работа прерывается только в крайнем случае, если не хватает ресурсов для активных приложений.
- Служебный процесс – процесс, содержащий Service, для которого была вызвана функция startService() , при условии, что данный Service сейчас работает.
- Процесс заднего фона. Данный процесс не имеет видимых пользователю Activity (была вызвана функция onStop()) . Как правило, существует множество фоновых процессов, работа которых завершается по принципу «последний запущенный закрывается последним», чтобы освободить ресурсы для приложений, работающих на переднем плане.
1.6.3. Services
Service – это некий процесс, который запускается в фоновом режиме. Как пример, Service может получать данные по сети, выполнять какие-либо длительные вычисления. Хорошим примером Service служит проигрыватель музыки. Пользователь может выбрать любую песню в проигрывателе, включить ее и закрыть плеер занявшись чем-нибудь другим. Музыка будет проигрываться в фоновом процессе.
Service проигрывания музыки будет работать, даже если Activity плеера закрыта.
Подобно Activity, Service имеет свои методы жизненного цикла:
- void onCreate()
- void onStart(Intent intent)
- void onDestroy()
В полном жизненном цикле Service существует два вложенных цикла:
- полная целая жизнь Service – промежуток между временем вызова метода onCreate() и временем возвращения onDestroy() . Подобно Activity , для Services производят начальную инициализацию в onCreate() и освобождают все остающиеся ресурсы в onDestroy() ;
- активная целая жизнь Service – начинается с вызова метода onStart() . Этому методу передается объект Intent, который передавался в startService() .
Как и Activities, Services запускаются в главном потоке процесса приложения. По этой причине их следует запускать в отдельном потоке, чтобы они не блокировали другие компоненты или пользовательский интерфейс.
1.6.4. Broadcast receivers
Broadcast receiver – это компонент, который ничего не делает, кроме того, что рассылает и реагирует на широковещательные сообщения. Примером широковещательных компонентов могут быть: сообщения об переходе на летнее/зимнее время, сообщения об минимальном заряде батареи и так далее.
Broadcast receiver не отображает пользовательский интерфейс, но может запустить Activity на полученное сообщение или использовать NotificationManager для привлечения внимания пользователя. Привлечь внимание пользователя можно, например, вибрацией устройства, проигрыванием звука или миганием вспышки.
Приемник широковещательных сообщений имеет единственный метод жизненного цикла: onReceive() . Когда широковещательное сообщение прибывает для получателя, Android вызывает его методом onReceive() и передает в него объект Intent , содержащий сообщение. Приемник широковещательных сообщений является активным только во время выполнения этого метода. Процесс, который в настоящее время выполняет Broadcast receiver, является приоритетным процессом и будет сохранен, кроме случаев критического недостатка памяти в системе.
Когда программа возвращается из onReceive() , приемник становится неактивным и система полагает, что работа объекта Broadcast receiver закончена. Процесс с активным широковещательным получателем защищен от уничтожения системой. Однако процесс, содержащий неактивные компоненты, может быть уничтожен системой в любое время, когда память, которую он потребляет, будет необходима другим процессам.
1.6.5. Content providers
Content providers предоставляют доступ к данным (чтение, добавление, обновление). Content provider может предоставлять доступ к данным не только своему приложению, но и другим. Данные могут размещаться в файловой системе, в базе данных.
Источник: intuit.ru
Жизненный цикл Android-приложений
Android проектировался таким образом, чтобы расширять возможности пользователей и сделать приложения интуитивно понятными. Например, пользователи приложения могут поворачивать экран, отвечать на уведомления и переключаться на другую задачу. Также у них есть возможность беспрепятственно продолжить работу с приложением после обработки какого-либо события.
Чтобы обеспечить такой UX, вам следует знать, как управлять жизненными циклами компонентов, таких как активности, фрагменты, сервисы, приложение в целом и так далее. Во время работы компонент проходит через состояния, определяемые его жизненным циклом. Система уведомляет о таких переходах через методы обратного вызова (callbacks).
Обратите внимание: Диаграммы описывают поведение в Android P / Jetpack 1.0.
Диаграммы показывают сценарии поведения по умолчанию, если не указано иное.
Жизненный цикл одной активности
Сценарий 1: завершение и повторный запуск приложения
Источники
Этот простейший сценарий показывает, что происходит, когда приложение с одной активностью завершается и снова запускается пользователем:
Сценарий 1: приложение завершено и перезапущено
Управление состоянием
- onSaveInstanceState() не вызывается (активность завершается, поэтому не нужно сохранять её состояние);
- onCreate() не принимает Bundle, так как предыдущая активность завершилась и не требует восстановления.
Сценарий 2: переход пользователя из приложения
Источники
- Нажатие кнопки «Home».
- Переключение на другое приложение (через кнопку «Overview», ответ на уведомление, приём входящего вызова и т. п.).
Сценарий 2: пользователь покидает приложение
В этом случае система остановит активность, но не будет сразу же завершать её.
Управление состоянием
Когда активность входит в остановленное состояние, система вызывает onSaveInstanceState() для сохранения состояния приложения на случай, если она завершит процесс впоследствии.
Предполагая, что процесс всё же не будет завершён, активность вместе со своим состоянием остаётся резидентной в памяти. Когда активность возвращается на передний план, её состояние доступно целиком и нет необходимости в повторной инициализации ранее созданных компонентов.
Сценарий 3: изменение конфигурации
Источники
- Смена конфигурации, например поворот экрана.
- Изменение размера окна в мультиоконном режиме.
Сценарий 3: поворот и другие изменения конфигурации
Управление состоянием
Изменения конфигурации вроде поворота и увеличения или уменьшения окна, должны позволять пользователям продолжать работу именно там, где они остановились:
- предыдущая активность полностью разрушается, но её состояние сохраняется и передаётся новой;
- в onCreate() и onRestoreInstanceState() передаётся один и тот же Bundle.
Сценарий 4: остановка приложения системой
Источники
- Вход в мультиоконный режим (API 24+) и потеря фокуса.
- Другое приложение, частично перекрывающее текущее (диалог покупки, запрос разрешения, сторонний диалог логина).
- Выбор Intent, например «Поделиться».
Сценарий 4 — остановка приложения системой
Сценарий не относится к следующим случаям:
- Диалоги в этом же приложении — показ AlertDialog или DialogFragment не приведёт к остановке активности.
- Уведомления — пользователь, получающий уведомление или открывающий их панель, не остановит активность.
Навигация и стек переходов
Примечание Показанные друг напротив друга группы событий отрабатываются параллельно. Поток выполнения может переключиться с одной группы событий на другую в любой момент времени, поэтому порядок вызовов методов из параллельных групп не определён. Однако последовательный порядок вызовов методов внутри группы гарантирован. Следующие сценарии не применяются к активностям и задачам с кастомным режимом запуска или заданным контекстом задачи (task affinity). За более подробной информацией обратитесь к документации на Android Developers.
Сценарий 1: навигация между активностями
Cценарий 1: завершение и повторный запуск приложения
В этом сценарии при старте новой активности первая останавливается (но не разрушается), что похоже на переход пользователя из приложения (по кнопке «Home»).
После нажатия на кнопку «Back» вторая активность разрушается и завершается.
Управление состоянием
Заметьте, что onSaveInstanceState() вызывается, а onRestoreInstanceState() — нет. Если изменение конфигурации произойдёт в то время, когда вторая активность открыта, то первая разрушится и будет снова создана, когда получит фокус обратно. Вот почему сохранение состояния важно.
Если система убьёт процесс для освобождения ресурсов, будет иметь место другой сценарий, в котором состояние потребуется восстановить.
Сценарий 2: активности в стеке переходов и изменения конфигурации
Сценарий 2: активности в стеке переходов и изменения конфигурации
Управление состоянием
Сохранение состояния важно не только для активности переднего плана. Все активности в стеке должны восстановить свои состояния после изменения конфигурации, чтобы заново построить пользовательский интерфейс.
Кроме того, система может завершить процесс почти в любой момент, так что следует быть готовым восстановить состояние в любой ситуации.
Завершение процесса
Когда Android нуждается в ресурсах, он завершает фоновые приложения.
Сценарий 3: завершение процесса
Управление состоянием
Несмотря на то, что весь стек переходов сохраняется, в целях эффективного использования ресурсов системы активности восстанавливаются только тогда, когда они заново создаются.
Узнать больше можно здесь.
Жизненный цикл фрагментов
В этой части обсудим поведение прикреплённых к активности фрагментов. Не смущайтесь сценария с добавлением фрагмента в стек переходов назад (подробнее о транзакциях фрагментов и стеке переходов здесь).
Сценарий 1: запуск активности с фрагментом и её завершение
Сценарий 1: запуск активности с фрагментом и её завершение
Гарантировано, что вызов onCreate() активности выполнится раньше соответствующих вызовов фрагментов. Однако противолежащие методы обратного вызова, такие как onStart() и onResume() , выполняются параллельно, и поэтому порядок их вызовов не определён. Например, система может выполнить метод onStart() активности перед методом onStart() фрагмента, но выполнить метод onResume() фрагмента перед методом onResume() активности.
Примечание Будьте осторожны при управлении потоками выполнения и избегайте состояния гонки.
Сценарий 2: поворот активности с фрагментом
Сценарий 2: поворот действия с фрагментом
Управление состоянием
Сохранение и восстановление фрагментов очень похоже на сохранение и восстановление активностей. Различие заключается в том, что у фрагментов нет метода onRestoreInstanceState() , но им доступен Bundle в методах onCreate() , onCreateView() и onActivityCreated() .
Фрагменты могут быть сохранены, то есть при изменении конфигурации активности будет использоваться один и тот же экземпляр фрагмента.
Сценарий 3: поворот активности с сохранённым фрагментом
Сценарий 3: поворот активности с сохранённым фрагментом
После поворота фрагмент не разрушается и не воссоздаётся, потому что после пересоздания активности используется тот же экземпляр фрагмента — при этом в onActivityCreated() всё ещё доступен объект состояния.
Не рекомендуется применять сохраняемые фрагменты, если они не используются для сохранения данных между изменениями конфигурации (в не UI-фрагменте). Класс ViewModel из библиотеки Architecture Components внутри реализован именно так, но он предоставляет более простой API.
ViewModels, полупрозрачные активности и режимы запуска
Модели представления (ViewModels)
Жизненный цикл модели представления достаточно простой — она имеет всего один метод обратного вызова, который называется onCleared() . Тем не менее, для модели представления есть различие между активностью и фрагментом:
Различие между активностью и фрагментом
Стоит обратить внимание, что инициализация случается всякий раз, когда вы получаете ViewModel , что обычно происходит в onCreate() .
Полупрозрачные активности
Из названия понятно, что у полупрозрачной активности полупрозрачный фон (как правило, совсем прозрачный). Таким образом, пользователь видит, что находится под ней.
Когда к теме активности применяется свойство android:windowIsTranslucent , диаграмма немного меняется: фоновая активность никогда не останавливается (только входит в состояние паузы), так что она может продолжать получать обновления UI:
Сравнение обычной и полупрозрачной активностей
Также при возвращении обратно к задаче, обе активности восстанавливаются и запускаются, и только полупрозрачная возобновляется:
Новая полупрозрачная активность: выход из приложения и повторное открытие
Режимы запуска
Рекомендованный способ работы с задачами и стеками переходов в своей основе прост — вы должны следовать поведению по умолчанию. За подробной информацией обратитесь к статье.
Если вам действительно нужен режим SINGLE_TOP , вот диаграмма:
Для сравнения посмотрите на следующей диаграмме режим singleTask (но, скорее всего, вам не нужно его использовать):
Если вы используете Navigation Architecture из Jetpack, то получите выгоду от поддержки Single Top и автоматического искусственного стека переходов.
Источник: tproger.ru
Android. Собеседование #1. Как работает Android; Структура приложения на Android
В статье можно прокачать фундаментальные знания, обязательно должен владеть Ты ими.
1. Расскажите об операционной системе Android
Android представляет собой операционную систему, написанную на основе ядра Linux. Ядро является главной частью ОС Linux, и практически полностью было перенесено в ОС Android, но с некоторыми модификациями, их около 250.
По умолчанию система назначает каждому приложению уникальный идентификатор пользователя Linux, этот идентификатор используется только системой и для приложения не доступен. Система устанавливает полномочия для всех файлов в приложении, с тем чтобы доступ к ним был разрешен только пользователю с идентификатором, назначенным этому приложению. Android запускает процесс, когда требуется выполнить какой-либо компонент приложения, а затем завершает процесс, когда он больше не нужен либо когда системе требуется освободить память для других приложений.
Над ядром операционной системы располагается Android Runtime – среда выполнения приложений. Ключевыми её составляющими являются виртуальная машина Dalvik (Art), а также набор стандартных библиотек. Каждое приложение в ОС Android запускается в собственном экземпляре виртуальной машины.
2. Как работает приложение на Android?
Программный код написанный разработчиком и все требуемые файлы данных и ресурсов, необходимые для корректной работы приложения компилируются в файл APK – программный пакет Android, который представляет собой файл архива с расширением .apk. В файле APK находится все, что требуется для работы Android-приложения, он позволяет установить приложение на любом устройстве под управлением системы Android.
Android не использует виртуальную машину Java (JVM) для выполнения файлов классов, вместо этого, в нём используется виртуальная машина Dalvik, не являющаяся истинной JVM и не работающая с Java байт-кодом. Начиная с версии Android 4.4 начала использоваться виртуальная машина Art (Android Runtime) и в версии Android 5.0 она полностью заменила Dalvik. На схеме приведены примеры исполнения обычного java-приложения, приложения для Android, а также приложения, созданного на фреймворке Xamarin.
Для платформы Android исходный java код транслируется в байт код и далее в далвик байт-код, с расширением .dex (Dalvik Executable Format), который понятен виртуальной машине Android.
3. Опишите структуру Android приложения
Рассмотрим структуру проекта приложения для ОС Android, которая представлена на изображении ниже.
Основные каталоги приложения:
src – cодержит исходный код приложения;
animator – содержит XML файлы, которые определяют свойства анимации;
anim – содержит XML файлы, которые определяют анимацию преобразований;
color – содержит XML файлы, которые определяют списки цветов;
drawable – содержит графические файлы или XML файлы, которые компилируются в графические ресурсы;
layout – содержит XML файлы, которые определяют расположение элементов пользовательского интерфейса;
menu – содержит XML файлы, которые определяют все меню приложения;
values – содержит XML файлы, которые определяют простые значения, таких ресурсов как, строки, числа, цвета.
mipmap – содержит изображение для лаунчера приложения
AndroidManifest.xml – содержит основную информацию о приложении
.gitignore – текстовый файл, содержащий список файлов и папок, которые будут игнорироваться системой контроля версий (VCS) и не будут загружены в удалённый репозиторий.
proguard-rules.pro – конфигурационный файл с правилами для утилиты Proguard
setting.gradle – в се модули, которые содержит проект указываются в данным файле
build.gradle – содержит информацию, используемую при построении проекта. Каждый модуль имеет свой файл build.gradle , который определяет подключенные библиотеки, конфигурацию построения проекта, специфичную для данного модуля
gradle.proeprties – файл, содержащий настройки используемые при сборке проекта
gradlew – используется Gradle Wrapper
local.properties – файл используется только Gradle, содержит путь к Android SDK
External Libraries – представляет собой перечень библиотек с расширением .jar, которые были подключены к нашему проекту
4. Что такое Android Manifest?
Каждое приложение в обязательном порядке должно содержать файл AndroidManifest.xml, который находится в корневой папке приложения. Файл содержит в себе всю необходимую информацию о приложении, которая требуется системе Android. Проанализировав информацию файла AndroidManifest.xml, система может выполнить необходимый код приложения.
Источник: stackofskills.com