4 марта 2014 г.

Компоненты приложений в Android.

Данная статья является компиляцией из двух источников:

Первый это статья из двух частей на сайте http://android-shark.ru
http://android-shark.ru/komponentyi-prilozheniy-v-android-chast-1/
http://android-shark.ru/komponentyi-prilozheniy-v-android-chast-2/

И вторая, это статья из альма-матер
http://developer.android.com/guide/components/fundamentals.html

По существу на http://android-shark.ru это просто очень хороший пересказ оригинальной статьи, хотя некоторые моменты из оригинала не были освещены.

Я тоже коротенько, в конспектном стиле и вольном переводе изложу здесь, то что есть в оригинале, а если кому-то будет мало, то линки приведены, можно смело туда идти и изучать.
И так поехали!
  • ОС Андроид это многопользовательская Linux система в которой каждое приложение это отдельный пользователь.
  • По умолчанию, система присваивает каждому приложению уникальный идентификатор – Linux User ID. Этот ID используется только системой и не известен приложению.
  • Каждое приложение запускается в своем собственном экземпляре виртуальной машины Dalvik, таким образом код каждого приложения изолирован от кода других приложений.
  • По умолчанию, каждое приложение запускается в своем собственном Linux процессе. Андроид запускает процесс всегда, когда любому компоненту приложения необходимо быть выполненным и убивает процесс когда в нем больше нет необходимости или когда системе нужны ресурсы для выполнения другого приложения.
Таким образом ОС Андроид использует систему или принцип минимальных привилегий (principle of least privilege), то есть, каждое приложение, по умолчанию, имеет доступ только к тем компонентам которые необходимы для ее работы и не более. Это создает очень безопасную среду, в которой приложение не может получить доступ к частям системы, для которой ей не дали разрешения.
Однако, есть способы для обмена данными с другими приложениями и для доступа к системным службам:
  • Можно организовать чтобы два приложения использовали один и этот же Linux User ID и таким образом они смогут получить доступ к данным друг друга. Для экономии системных ресурсов приложения с одним и тем же User ID можно запускать в одном Linux процессе и разделять одну и ту же VM (для этого приложения должны быть подписаны одним и тем же сертификатом).
  • Приложение может запросить разрешение на доступ к устройству и данным таким, как контакты пользователя, SMS-сообщения, SD-карты, камера, Bluetooth и многое другое. Эти разрешения дает непосредственно пользователь, соглашаясь с тем что требует приложение в начале установки. Все эти разрешения определяются в файле AndroidManifest.xml.
Интересной чертой операционной системы Android является тот факт, что приложение в ней может использовать для своего функционала элементы других приложений, если, конечно, они предоставляют такой доступ.
Например, если нашему приложению требуется отобразить прокручиваемый список изображений, а другое приложение уже имеет реализованный подходящий скроллер, открытый для других приложений, то можно просто вызвать его для осуществления этого действия и не разрабатывать свой собственный.
При этом код нашего приложения не смешивается с кодом другого и не компонуется с ним. Скорее, он просто запускает некоторый кусок другого файла, когда возникает такая необходимость.
Для обеспечения такого принципа работы, система должна быть способна запускать процесс приложения тогда, когда потребуется любая его часть и создавать экземпляры java-объектов именно для этой части. Поэтому приложения Android не имеют единой точки входа в программу, как это принято в большинстве систем (например, main() в Си). Вместо этого их код представляет собой набор некоторых отдельных целостных сущностей, компонент, из которых система по мере необходимости может создавать экземпляры и использовать их. Можно выделить четыре типа таких сущностей-компонент. Поговорим о каждой в отдельности.

Activities

Activity представляет собой внешний пользовательский интерфейс для одной операции, которую может совершить пользователь. Если упростить, то это просто один текущий экран как некоторая единица активности, своего рода кадр с одним пользовательским действием.
Здесь и далее будет использоваться термин activity без перевода, как некоторое имя собственное. Хотя дословный перевод, «активность» или «действие», хорошо передает общий смысл компонента.
Например, activity может предоставить список пунктов меню, которые может выбрать пользователь или отобразить фотографии с их подписями. Или другой пример – приложение для мгновенного обмена сообщениями может использовать одно activity для того чтобы отобразить лист контактов, другое – чтобы создать сообщение для выбранного контакта, третье – чтобы посмотреть историю сообщений или выполнить настройки и так далее.
Все activity текущего приложения работают вместе и формируют единый пользовательский интерфейс, однако при этом они независимы между собой. Каждое из них реализовано как подкласс базового класса Activity, обеспечивающего создание окна, в котором программист может поместить визуальный интерфейс.
Приложение может состоять из всего одного activity или сразу из нескольких, как упомянутый ранее в качестве примера мессенджер. Какими именно будут activity и сколько их будет, зависит от конкретного приложения и его дизайна. Как правило, одно из activity помечается как первое, это означает, что оно будет предоставлено пользователю при запуске приложения. Одно activity может запускать другое. Таким образом, переход от одного activity к другому осуществляется тогда, когда текущее activity вызывает следующее.
Каждое activity предоставляет окно по умолчанию. Обычно окно создается в полноэкранном виде, но оно также может и не занимать весь экран и находиться поверх других окон. Activity также может задействовать дополнительные окна – например, всплывающее диалоговое для взаимодействия с пользователем в процессе работы activity, или окно для предоставления текущей информации при выборе какой-нибудь важной опции.
Визуальное содержание окна строится с помощью иерархии визуальных компонентов (или представлений) – объектов, производных от базового класса View. Каждый компонент представляет собой просто прямоугольное пространство внутри окна. Родительские компоненты содержат дочерние и организуют их расположение. Иерархию компонент можно представить в виде дерева, а те элементы, которые находятся в самой нижней его части (“листья”) и не имеют дочерних компонент, отрисовывают прямоугольные области и ожидают действий пользователя на этом участке. Таким образом осуществляется интерактивное взаимодействие с пользователем. К примеру, такое представление может отображать на экране маленькую иконку и инициировать какое-нибудь действие, когда пользователь на неё нажмет. В операционной системе Android уже есть набор готовых визуальных компонент, которые доступны для использования разработчиками. Набор включает в себя кнопки, текстовые поля, полосы прокрутки, меню, флажки-переключатели и многое другое.
Для того чтобы поместить в окно такую иерархию, нужно вызвать метод Activity.setContentView(). Параметром метода является экземпляр класса View, лежащий в корне иерархии.

Services

Services(сервисы) представляют из себя компоненты, которые работают в фоновом режиме. Сервис, как правило, требуется для длительных операций или для обеспечения работы удаленных процессов, но в общем случае это просто режим, который функционирует, когда приложение не в фокусе. Примером такого процесса может стать прослушивание музыки в то время, когда пользователь делает что-то другое или получение данных по сети без блокирования текущей активности. Сервис сам по себе не предоставляет пользовательского интерфейса, то есть с пользователем не взаимодействует, а запускается, управляется и связан с другими компонентами, например, activity. Также может запускаться вместе с системой. Сервисы реализованы в виде подкласса Service.

Content providers

Данный компонент управляет наборами данных, которые приложения предоставляют другим. Эти данные могут храниться в файловой системе, базах данных SQLite, в сети, или в любом другом постоянном месте, к которому приложение может иметь доступ. Посредством content provider другое приложение может запрашивать данные и, если выставлены соответствующие разрешения, изменять их. Например, система Android содержит content provider, который управляет пользовательской информацией о контактах. Он позволяет любому приложению, обладающему соответствующими правами вызывать составляющие этого компонента для того, чтобы считывать, записывать или изменять информацию о конкретном человеке.
В более общем случае, content provider можно использовать для чтения и записи данных, которые используются приложением и не являются открытыми для других. Например, приложение Note Pad использует такой компонент для сохранения сделанных записей.
Данные компоненты реализуются как подкласс ContentProvider. И для того, чтобы другие приложения могли совершить операции с данными, им необходимо предоставить стандартный набор API.

Broadcast receivers

Этот компонент отвечает за распространение общесистемных сообщений, отслеживание и реагирование на действия. Многие оповещения идут от системы, например, сообщения о том что заряд батареи мал или экран выключен. Приложения также могут инициировать такие оповещения, например, сигнализировать о том, что информация загружена на устройство и доступна к использованию. Как и сервисы, broadcast receiver не предоставляет пользовательского интерфейса, однако, он способен создавать уведомления в строке состояния, чтобы предупреждать пользователя о том, что произошло какое-то событие. Однако чаще broadcast receiver взаимодействует с другими компонентами для того, чтобы самому выполнять минимальный объем работы. Так, он может инициировать сервисы для выполнения действий, привязанных к какому-то событию.
Компонент реализуется как подкласс BroadcastReceiver и каждая передача представляется как объект класса Intent.

 Активация компонентов

Еще раз заострим внимание на уникальном свойстве системы Android который заключается в том, что любое приложение может использовать компоненты другого приложения. Например, если вы хотите, чтобы пользователь в вашем приложении сделал фото с помощью камеры устройства, то возможно, есть другое приложение, которое делает это, что и ваше приложение может использовать его функционал, вместо того, чтобы вам самим разрабатывать эту функцию в своем приложении. Вместо этого, вы можете просто запустить компонент в приложение камеры, который делает снимок. Этот компонент сделает фото и вернет его в ваше приложение, так что вы можете использовать это фото в вашем приложении. А для пользователя это будет казаться, как если бы функционал камеры на самом деле является частью вашего приложения.
Когда система запускает компонент приложения, то она запускает процесс данного приложения (если он еще не запущен) и создает классы, необходимые для этого компонента. Например, если ваше приложение запускает Activity приложения камеры, чтобы сделать снимок, то эта Activity, запускается в процессе, который принадлежит приложению камеры, а не процессу вашего приложения. Поэтому, в отличие от приложений на большинстве других систем, приложения для Android не имеют единой точки входа (нет функции main (), например).
Поскольку система запускает каждое приложение в отдельном процессе с правами доступа к файлам, которые ограничивают доступ к этим файлам другим приложениям, приложения не могут непосредственно активировать компонент другого приложения. Однако система Android может. Поэтому, чтобы использовать компонент другого приложения, вы должны сообщить об этом системе Андроид, что у вас есть намерение (intent) запустить компонент какого-либо приложения, и система запустит этот компонент для вас.
Три из четырех типов компонент – Activity, Services и Broadcast Receivers активируются через асинхронные сообщения называемые intent (намерение). Интенты (intents) связывают различные компоненты друг с другом в реальном времени (об интентах можно думать как о посланниках, которые запрашивают какое либо действие от компонента) и это безотносительно того, является ли данный компонент частью вашего приложения или другого.
Четвёртый тип компонентов – Content Provider не активируется интентами (intents). Content Provider активируется запросом от ContentResolver.

AndroidManifest.xml

Чтобы система Андроид могла запустить компонент приложения, она должна узнать о его существовании из файла AndroidManifest.xml. Ваше приложение должно объявить все свои компоненты в этом файле, который должен быть в корне каталога каждого проекта.

Кроме этого, напомним еще раз, манифест-файл выполняет другие функции:
  • Определяет пользовательские разрешения которые необходимы приложению, такие как доступ в Интернет или чтение контактов.
  • Объявление минимального API уровня (версии Android), необходимого для приложения.
  • Объявление аппаратных и программных требований, такие как камера, Bluetooth, или мультитач экран.
  • API библиотек с которые необходимы приложению, например библиотеки Google Maps.
  • и много чего еще Улыбка
Но все же основная задача манифеста сообщить системе о компонентах приложения. Например, можно объявить Activity (деятельность) следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:icon="@drawable/app_icon.png" ... >
        <activity android:name="com.example.project.ExampleActivity"
                  android:label="@string/example_label" ... >
        </activity>
        ...
    </application>
</manifest>

В элементе <application> атрибут Android:icon указывает на ресурсы для иконки приложения.

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

Для определения компонентов используются:
  • <activity> для Activity (деятельности)
  • <service> для Service (сервисы)
  • <receiver> для Broadcast reciever (получатели широковещательных сообщений)
  • <provider> для Content providers (поставщики данных)

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

Объявление возможностей компонента

Как уже говорилось в разделе «Активация компонентов», для вызова Activity (деятельность), Service (сервис) и Broadcast receiver (получатель широковещательных сообщений) можно использовать класс Intent. Сделать это можно явно, задав конкретное имя компонента, или не явно, а этом случае описывается только тип действия, который нужно выполнить (и, возможно, данные, необходимые для него). Система сама находит компонент устройства, который может выполнить действия и запускает его. Если найдено несколько подходящих компонентов, то пользователь выбирает, какой из них использовать.

Система определяет компоненты, которые могут реагировать на намерение путём сравнения полученного Intent (намерения) от приложеия, с Intent filters (фильтр намерений), определённых в файлах манифеста других приложений. 

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

Например, приложение электронной почты с Activity (деятельностью) для создания новых сообщений может объявить Intent filter (фильтр намерения) в своём файле манифеста запускаться на запрос "send" (отправить). Например так (строки 5,6):
<manifest ... >
    ...
    <application ... >
        <activity android:name="com.example.project.ComposeEmailActivity">
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <data android:type="*/*" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Activity (деятельность) в стороннем приложении создаёт Intent (намерение) с типом действия "send" (ACTION_SEND), которое система сопоставит с приложением электронной почты и запустит нужную Activity (деятельность).

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

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

Например, если приложение требует камеру и использует API, введённые в Android версии 2.1 (API уровень 7), надо записать эти требования в файл манифеста. Например так:
<manifest ... >
    <uses-feature android:name="android.hardware.camera.any"
                  android:required="true" />
    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
    ...
</manifest>

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

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

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

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

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

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

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

Комментариев нет:

Отправить комментарий