Основы Android приложений

Android приложения написаны на языке программирования Java. Инструменты Android SDK компилируют ваш код — включая все данные и ресуры — в файл APK (Android Package): пакет Android, который является архивом файлов с расширением .apk. Один APK файл включает все содержимое отдельного Android приложения и этот файл Android устройства используют для установки приложения.

После установки на устройство, каждое приложение работает в его собственной защищенной песочнице:

  • Операционная система Android – это многопользовательская система Linux, в которой каждое приложение запускается под отдельным пользователем.
  • По умолчанию, система присваивает каждому приложению уникальный идентификатор пользователя Linux (этот ID используется системой и неизвестен приложению). Система устанавливает разрешения для всех файлов приложения и только пользователь с таким ID может иметь к ним доступ.
  • Каждый процесс выполняется в своей собственной виртуальной машине, поэтому приложение выполняется изолировано от остальных приложений.
  • По умолчанию, каждое приложение запускается в своем собственном отдельном процессе. Android запускает процесс, когда требуется выполнить компонент приложения и останавливает процесс, когда компонент больше не требуется, или если системе недостаточно памяти для выполнения других приложений.

Таким образом, в системе Android реализован принцип наименьших привилегий. Так что по умолчанию каждое приложение имеет доступ только к компонентам, которые необходимы ему для работы и не более того. Благодаря этому создается безопасная среда, в которой приложение не может получить доступ к элементам системы, для которых не получено соответствующее разрешение.

Однако, существуют способы обмена данными между приложениями и доступа к системным сервисам:

  • Возможно установить для двух приложений общий идентификатор, в этом случае они смогут получить доступ к файлам друг друга. Для экономии ресурсов системы, приложения с одинаковым идентификатором могут также могут запускаться в одном и том же процессе и использовать одну и ту же виртуальную машину (приложения при этом должны быть подписаны одним и тем же сертификатом).
  • Приложение может запросить разрешение на доступ к данным, например контактам, SMS сообщениям, присоединенным хранилищам (SD карты), камере, Bluetooth и другим. Все разрешения должны быть подтверждены пользователем во время установки приложения.

Это основы того, как Android приложение существует в системе. Остальная часть текущего документа познакомит вас:

  • С базовыми компонентами фреймворка, которые определяют ваше приложение.
  • С файлом манифеста, в котором описаны компоненты и требования к устройству для вашего приложения.
  • С ресурсами, которые хранятся отдельно от кода и позволяют изящно оптимизировать ваше приложение для различных конфигураций Android устройств.

Компоненты приложения

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

Существует четыре разных типа компонентов. Каждый из них служит для различных целей, имеет свой собственный жизненный цикл, который определяет, как компонент создается и уничтожается.

Вот эти четыре типа:

Явления (Activities)

Явления представляют собой единый экран с пользовательским интерфейсом. Например, почтовый клиент может использовать одно явление для отображения списка входящих писем, другое явление для чтения конкретного письма, а третье явление для написания нового сообщения. И хотя все явления работают вместе, чтобы сформировать общую функциональность приложения, каждое из них независимо от других. Кроме того, приложения могут запускать явления друг друга (если это разрешено). Например, приложение фотокамера может запустить явление почтового клиента для создания нового письма с только что отснятой фотографией в качестве вложения.

Явления реализуются как подклассы базового класса Activity, о них вы можете подробнее узнать в разделе Явления.

Сервисы (Services)

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

Службы реализуются как подклассы базового класса Service, о них вы можете подробнее узнать в разделе Сервисы.

Поставщики содержимого

Поставщики содержимого управляют общими данными в приложении. Вы можете хранить данные в файловой системе, в базе данных SQLite, в сети, в любом другом постоянном хранилище, к которому приложение имеет доступ. Через поставщики содержимого, другие приложения могут получить или модифицировать данные вашего приложения (если это разрешено). Например, Android предоставляет поставщик содержимого для управления контактными данными. Таким образом, любое приложение, которое имеет соответствующее разрешение, может запросить поставщики содержимого (например ContactsContract.Data) для чтения или изменения информации о каком-либо человеке.

Поставщики содержимого также удобны для чтения и записи не открытых данных приложения. Например, приложение NotePad использует поставщики содержимого для сохранения записей.

Поставщики содержимого реализуются как подклассы базового класса ContentProvider и должны содержать стандартный набор методов, которые позволят другим приложениям выполнять транзакции. Подробную информацию смотрите в разделе Поставщики содержимого.

Широковещательные приемники

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

Широковещательные приемники реализуются как подклассы базового класса BroadcastReceiver и каждая рассылка передается как объект типа Intent. За подробной информацией обращайтесь к документации по классу BroadcastReceiver.

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

Когда система запускает компонент, запускается процесс для приложения (если оно не было уже запущено) и создаются экземпляры классов, необходимые для работы компонента. Например, если ваше приложение запустило явление другого приложения, это явление будет работать в процессе другого приложения, а не вашего. Поэтому, в отличие от приложений в большинстве других систем, Android приложения не имеют единой точки входа в программу (например, нет основной функции main()).

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

Запуск компонентов

Три из четырех типов компонентов — явления, сервисы и широковещательные приемники — запускаются с помощью асинхронного сообщения, которое называется намерение (intent). Намерения связывают отдельные компоненты друг с другом во время выполнения (вы можете думать о них как о посыльных, которые запрашивают действия у других компонентов), независимо от того, принадлежит ли компонент вашему приложению или какому-либо другому.

Намерения создаются с помощью объектов типа Intent, которые определяют сообщение для запуска конкретного компонента или компонента заданного типа. Такие намерения называются соответственно явные и неявные.

Для явлений и сервисов, намерения определяют действие для выполнения (например, «что-то показать» или «что-то передать») и могут содержать URI данных. Например, намерение может передать запрос явлению, чтобы последнее показало изображение или веб-страницу. В некоторых случаях, вы можете запустить явление, чтобы получить от него результат. В таких случаях, явление возвращает результат так же в объекте Intent (например, вы можете оформить намерение для выбора контакта, и вам вернется другое намерение, содержащее URI, который указывает на выбранный контакт).

Для широковещательных приемников, намерения просто описывают сообщение, которое будет разослано (например, рассылка о низком заряде батареи может содержать только строку «батарея разряжена»).

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

Вот различные методы для запуска каждого типа компонентов:

  • Вы можете запустить явление (или заставить его сделать что-то новое), передав объект намерения Intent в метод startActivity() или startActivityForResult() (если вы хотите, чтобы явление вернуло результат работы).
  • Вы можете запустить сервис (или передать новые инструкции на уже работающий), передав объект намерения Intent в метод startService(). Или можете связать сервис передав Intent в метод bindService().
  • Вы можете инициировать рассылку передав намерение в методы sendBroadcast(), sendOrderedBroadcast() или sendStickyBroadcast().
  • Вы можете выполнять запросы к поставщикам содержимого с помощью метода query() класса ContentResolver.

Подробную информацию об использовании намерений, смотрите в разделе Намерения и фильтры. Информация о запуске различных компонентов также представлена в следующих разделах: Явления, Сервисы, Широковещательные приемники и Поставщики содержимого.

Файл манифеста

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

Кроме описания компонентов приложения, манифест служит также для следующих вещей:

  • Указание разрешений, которые требуются приложению, например доступ в интернет или чтение контактов.
  • Объявление минимального уровня API, который требуется для работы приложения.
  • Объявление программных и аппаратных зависимостей, например камеры, bluetooth или экран с поддержкой нескольких прикосновений.
  • Указание библиотек, который должны быть подключены к приложению, например Google Maps Library.
  • И другое

Описание компонентов

Первичной задачей файла манифеста является информирование системы о компонентах приложения. Например, манифест может описывать явление следующим образом:

Атрибут android:icon элемента <application> ссылается на ресурс, в котором хранится иконка приложения.

Атрибут android:name элемента <activity> содержит полное имя класса явления (он является наследником базового класса Activity), а атрибут android:label содержит заголовок явления, который будет показан пользователю.

Вам нужно описать все компоненты приложения, используя следующие теги:

  • <activity> для явлений
  • <service> для сервисов
  • <receiver> для широковещательных приемников
  • <provider> для поставщиков содержимого

Если вы создадите в коде явления, сервисы или поставщики содержимого, но не объявите их в файле манифеста, они будут невидимы для системы и не смогут быть запущены. Однако, широковещательные приемники могут быть либо объявлены в манифесте, либо созданы в коде динамически (объекты типа BroadcastReceiver) и зарегистрированы в системе с помощью метода registerReceiver().

Подробную информацию о структуре файла манифеста, смотрите в разделе Файл AndroidManifest.xml.

Описание возможностей компонентов

Как было сказано выше, вы можете использовать объект типа Intent для запуска явлений, сервисов и широковещательных приемников. Вы можете сделать это явно указав имя компонента в намерении (используя имя класса компонента). Однако, реальная мощь намерений скрывается в концепции неявных намерений. Неявные намерения просто описывают тип действия для выполнения (и, возможно, необходимые для действия данные), а система автоматически ищет компонент, который может выполнить действие с заданным типом, и запускает его. Если существует несколько компонентов, способных выполнить действие, пользователь сможет выбрать желаемый компонент из списка.

Поиск компонентов происходит следующим образом: система получает намерение и сверяет его с фильтрами намерений, описанных в манифесте каждого из приложений на устройстве.

Если вы описали явление в манифесте, вы можете по желанию добавить к нему фильтры намерений, которые говорят о возможностях явления, то есть какие намерения это явление может обрабатывать. Чтобы описать фильтр, необходимо добавить к описанию компонента дочерний элемент <intent-filter>.

Например, если вы создали почтовый клиент, который включает явление для создания нового письма, вы можете описать фильтр для ответа на намерения с действием “send” (чтобы отправить новое письмо), например так:

Теперь если другое приложение создаст намерение с действием ACTION_SEND и передаст его в метод startActivity(), система может запустить ваше явление, чтобы пользователь написал и отправил письмо.

Подробная информация содержится в разделе Намерения и фильтры.

Описание требований приложения

Существует много различных устройств на Android, и не у всех из них одинаковые возможности. Для того, чтобы предотвратить установку приложения на устройства, которые не поддерживают необходимые для работы приложения возможности, важно указать аппаратные и программные зависимости в файле манифеста. Многие записи являются информационными и система их не считывает, но внешний сервис Google Play использует их и выдает пользователям только совместимые с их устройствами приложения.

Например, если вашему приложению требуется камера и Android не ниже 2.1 (API 7), вы должны указать в манифесте что-то подобное:

Теперь ваше приложение не сможет быть установлено из Google Play на устройства, в которых нет камеры или версия Android ниже 2.1.

Однако, вы можете также сообщить, что ваше приложение использует камеру, но ее наличие не является обязательным. В таком случае, установите атрибуте required в значение false и проверяйте наличие камеры в программном коде.

Подробная информация о создании совместимости с разными устройствами, содержится в разделе Совместимость устройств.

Ресурсы приложения

Android приложения состоят не только из кода – им требуются ресурсы, которые отделены от программного кода, например изображения, звуковые и другие файлы, которые влияют на внешний вид приложения. К примеру вам потребуется создавать анимацию, меню, стили, цвета и разметку явлений с помощью XML файлов. Использование ресурсов в приложении делает простым обновление различных характеристик без модификации исходного кода, для этого просто нужно загрузить альтернативные ресурсы, и позволяет оптимизировать приложение под различные конфигурации устройств (например разные языки или размеры экранов).

Каждому ресурсу вашего проекта, SDK присваивает уникальный целочисленный идентификатор, которые вы можете использовать для ссылки на ресурсы из программного кода или из XML файлов других ресурсов. Например, если ваше приложение содержит изображение с именем logo.png (которое хранится в каталоге res/drawable/), SDK сгенерирует уникальный идентификатор с именем R.drawable.logo, который вы можете использовать для ссылки на изображение и вставки этого изображения в пользовательский интерфейс.

Одним из наиболее важных аспектов отделения ресурсов от кода является возможность создавать различные ресурсы для различных конфигураций устройств. Например, вы можете создать строковые константы для разных языков и хранить их в различных файлах. Основываясь на спецификаторе языка, который добавляется к названию директорий (например res/value-fr/ для французского) и настройках языка на устройстве, система сама выберет подходящий файл для пользовательского интерфейса.

Спецификатор – это короткая строка, которая добавляется к имени директории, чтобы указать конфигурацию устройства, для которого ресурсы из данной директории будут использоваться. Android поддерживает множество различных спецификаторов для создания альтернативных ресурсов.Например, если устройство находится в портретной ориентации, вы можете захотеть выравнять кнопки вертикально, если в ландшафтной – горизонтально. Чтобы менять макет в зависимости от ориентации экрана, необходимо создать два варианта разметки и применить спецификатор к директориям, в которых разметка будет храниться. Система автоматически будет выбирать нужную.

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

Добавить комментарий