Файл: Debian Таненбаум Бос.pdf

ВУЗ: Не указан

Категория: Книга

Дисциплина: Операционные системы

Добавлен: 29.10.2018

Просмотров: 48047

Скачиваний: 190

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

906  

 Глава 10. Изучение конкретных примеров: Unix, Linux и Android 

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

Листинг 10.6. Интерфейс для управления интервалом синхронизации службы sync

package com.example.email

interface ISyncControl {

int getSyncInterval();
    void setSyncInterval(int seconds);
}

Чтобы воспользоваться этим, другой процесс может привязаться к нашей прикладной 
службе, получив доступ к ее интерфейсу. Тем самым будет создана связь между двумя 
приложениями (рис. 10.38). Этот процесс проходит следующие этапы:

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

привязаться к службе.

2.  Если служба еще не создана, диспетчер активностей создает ее в процессе при-

ложения службы.

3. Служба возвращает экземпляр IBinder для своего интерфейса диспетчеру актив-

ностей, который теперь удерживает этот IBinder в своей записи ServiceRecord.

4.  После того как диспетчер активностей получил IBinder службы, этот экземпляр 

может быть отправлен в адрес исходного клиентского приложения.

5.  Теперь, когда у клиентского приложения имеется IBinder службы, оно может про-

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

2. Создает

3. Возвра-
щает

4. Отправ-
ляет

1. Привя-
зывает

Процесс клиентского приложения

5. Вызывает службу

SyncService

IBinder

IBinder

IBinder

IBinder

IBinder

ServiceRecord

(SyncService)

Процесс почтового приложения

Диспетчер активностей 

в процессе system_server

ОСТ

АНОВ-

ЛЕННАЯ

Рис. 10.38. Привязка к прикладной службе


background image

10.8. Android   

907

Получатели

Получатель

 (receiver) принимает случающиеся события (как правило, внешние) обыч-

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

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

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

 Диспетчер активностей 

в процессе system_server

Процесс приложения Календарь

Процесс почтового приложения

Процесс приложения браузера

SyncControlReceiver

SyncControlReceiver

CleanupReceiver

BroadcastRecord

DEVICE_STORAGE_LOW

SyncControlReceiver

(Calendar app)

SyncControlReceiver

(Email app)

CleanupReceiver

(Browser app)

Рис. 10.39. Отправка рассылки получателям приложений

Получатели работают только как разовые операции. Когда происходит событие, систе-
ма находит всех заинтересованных в нем получателей и доставляет им событие, а они 
после потребления события завершают свою работу. Здесь нет записи ReceiverRecord
подобной той, что мы видели для других компонентов приложения, поскольку отдель-
но взятый получатель является всего лишь переходным объектом на время действия 
отдельной рассылки. При каждой отправке получателю новой рассылки создается 
новый экземпляр класса этого получателя.


background image

908  

 Глава 10. Изучение конкретных примеров: Unix, Linux и Android 

Поставщики контента

Последним нашим компонентом приложения будет поставщик контента (content 
provider), который является основным механизмом, используемым приложением для 
обмена данными с другими приложениями. Все взаимодействия с поставщиком контен-
та осуществляются через унифицированные индикаторы ресурса (URI), с использова-
нием формата content: схема. Полномочия URI используются для поиска правильной 
реализации поставщика контента, с которым требуется наладить взаимодействие.

Например, в нашем почтовом приложении из листинга 10.5 поставщик контекста 
указывает, что его полномочие — это com.example.email.provider.email. Стало быть, URI-
индикаторы, работающие на этот поставщик контента, должны начинаться с

content://com.example.email.provider.email/

Суффикс для этого URI интерпретируется самим поставщиком для определения того, 
какие данные внутри него будут доступны. В этом примере обычным соглашением 
будет то, что URI

content://com.example.email.provider.email/messages

означает список всех почтовых сообщений, а

content://com.example.email.provider.email/messages/1

предоставляет доступ к одному сообщению с номером ключа 1.

Для взаимодействия с поставщиком контента приложения всегда проходят через ис-
пользование системного API-интерфейса по имени ContentResolver, где у большинства 
методов имеется начальный URI-аргумент, показывающий данные, с которыми нужно 
работать. Одним из наиболее востребованных методов ContentResolver является query
осуществляющий запрос к базе данных по заданному URI и возвращающий Cursor для 
извлечения структурированных результатов. Например, извлечение сводки обо всех 
доступных почтовых сообщениях будет иметь примерно следующий вид:

query("content://com.example.email.provider.email/messages")

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

1. Приложение вызывает ContentResolver.query для начала операции.

2.  URI-полномочия вручаются диспетчеру активностей, чтобы он нашел (через дис-

петчер пакетов) соответствующего поставщика контента.

3.  Поставщик контента еще не работает, поэтому он создается.

4.  После создания поставщик контента возвращает диспетчеру активностей свой 

IBinder, реализуя тем самым системный интерфейс IContentProvider.

5.  IBinder поставщика контента возвращается в распознаватель контента —Content-

Resolver.

6.  Теперь распознаватель контента может завершить исходную операцию query

вызвав соответствующий метод в отношении AIDL-интерфейса, возвращающий 
результат Cursor.

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


background image

10.8. Android   

909

Диспетчер активностей 

в процессе system_server

Процесс почтового приложения

ProviderRecord
(EmailProvider)

EmailProvider

ContentResolver

1. query()

Процесс клиентского приложения

3. Создает

IBinder

IContentProvider.Stub

IContentProvider.Proxy

4. Возвращает

2. Ищет 
полномочия

IBinder

IBinder

6. query()

5. Возвращает

Рис. 10.40. Взаимодействие с поставщиком контента

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

1.  Создается и отправляется системе запрос на общий контент, включающий URI 

данных, подлежащих совместному использованию.

2.  Система требует от ContentResolver MIME-тип данных, указанных в этом URI. Это 

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

3.  Система ищет все активности, которые могут получить данные этого идентифи-

цированного MIME-типа.

4.  Пользователю показывается пользовательский интерфейс для выбора одного из 

возможных получателей.

5.  Когда одна из активностей выбрана, система ее запускает.

6.  Активность, обрабатывающая общий контент, получает URI совместно исполь-

зуемых данных, извлекает его данные с помощью ContentResolver и выполняет со-
ответствующую операцию: создает адрес электронной почты, сохраняет его и т. д.

10.8.9. Намерения

Деталь, которую мы еще не рассматривали в манифесте приложения, показанном 
в листинге 10.5, относится к тегам <intent-filter>, включенным вместе с объявлением 
активностей и получателя. Это часть существующего в Android свойства «намерение» 
(intent), являющегося краеугольным камнем способа, который позволяет разным при-
ложениям идентифицировать друг друга, обеспечивая возможности взаимодействия 
и совместной работы.

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


background image

910  

 Глава 10. Изучение конкретных примеров: Unix, Linux и Android 

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

Есть два основных типа намерений: явные и неявные. Явное намерение (explicit intent) 
напрямую идентифицирует один конкретный компонент приложения, в понятиях 
оболочки Linux он является эквивалентом предоставления команде абсолютного пути. 
Наиболее важной частью такого намерения является пара строк, называющая компо-
нент: имя пакета целевого приложения и имя класса компонента внутри этого прило-
жения. Теперь снова сошлемся на активность, показанную на рис. 10.32 в приложении, 
чей манифест показан в листинге 10.5. Явным намерением этого компонента будет один 
из пакетов по имени com.example.email и имя класса com.example.email.MailMainActivity.

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

Неявное намерение

 (implicit intent) описывает характеристики желаемых компо-

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

Основная возможность Android по совместному использованию объектов, ранее пока-
занная на рис. 10.35, иллюстрирующем совместное использования снимка, сделанного 
пользователем при помощи камеры, в почтовом приложении, является хорошим при-
мером неявного намерения. В нем приложение камеры создает намерение, описываю-
щее то действие, которое должно быть выполнено, а система находит все активности, 
которые потенциально могут выполнить это действие. Совместное использование 
запрашивается через действие намерения android.intent.action.SEND, и в листинге 10.5 
мы можем увидеть, что имеющаяся в почтовом приложении активность compose объ-
являет, что она может выполнить это действие.

У разрешения намерения может быть один из трех итогов: 

 

 соответствие не найдено;

 

 найдено одно уникальное совпадение;

 

 существует несколько активностей, способных справиться с намерением. 

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

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