T.M. SoftStudio

feci quod potui, faciant meliora potentes

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

Программирование мобильных приложений для платформы Android

Лекция 5. Класс Intent. Часть 1

В нашем последнем уроке мы говорили о классе активности, и я показал, как один вид активности может программно запустить другую активность с помощью создания объекта Intent, а затем передачи этого объекта намерения методу startActivity или startActivityForResult.

Сегодня мы собираемся бросить более глубокий взгляд на намерения.

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

И я начну с представления класса Intent.

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

После этого, я буду говорить о двух путях, которыми Android решает, какая активность должна быть запущена, когда метод, например, startActivity вызывается.

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

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

Класс Intent является в основном структурой данных, которая служит, по меньшей мере, двум целям в Android.

Одна из них – Intent может указать операцию, которую вы хотите выполнить, и другая – Intent может представлять событие, которое произошло в системе и о котором вы хотите уведомить другие компоненты.

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

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

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

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

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

Итак, давайте поговорим теперь о видах информации, которая может быть определена в пределах намерения.

Например, мы поговорим о полях намерения, включая действия, данные, категории, MIME-тип, целевой компонент, дополнения и флаги.

Поле действие – это строка, представляющая или именующая операцию, которая будет производиться.

Некоторые встроенные поля включают:

    ACTION_DIAL, что означает – я хочу набрать телефонный номер.

    ACTION_EDIT, я хочу показать некоторые данные для редактирования пользователем.

    ACTION_SYNC, я хочу синхронизировать некоторые данные на моем устройстве с данными на сервере.

    ACTION_MAIN, я хочу начать активность в качестве начальной активности приложения.

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

Например, вы можете передать строку действия в качестве параметра конструктору намерения.

Кроме того, вы можете создать пустое намерение, а затем вызвать методы, передавая строку действия снова в качестве параметра.

Intents также имеет поле данных, которое представляет данные, связанные с намерением.

Эти данные отформатированы как Uniform Resource Identifier или URI.

И один из примеров данных намерения является URI, который указывает данные карты.

Вы также, возможно, помните, что мы видели нечто подобное в предыдущих уроках, как часть MapLocation приложения.

Другим примером является URI с указанием телефонного номера, который вы хотите набрать.

И обратите внимание, что строки, которые представляют низлежащие данные, сначала пропускаются через uri.parse метод, который берет строку, а затем возвращает объект URI.

Вы можете установить данные намерения различными способами.

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

Категория намерения представляет дополнительную информацию о видах компонентов, которые могут обрабатывать или должны обрабатывать это намерение.

Некоторые встроенные категории включают:

CATEGORY_BROWSABLE, означает, что активность может быть вызвана с помощью браузера, через ссылку URI.

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

Intent также имеет поле типа, которое определяет mime-тип данных намерения.

Некоторые встроенные MIME-типы включают различные форматы изображений, такие как image/png для PNG изображений, и image/jpg или jpg для JPG изображений.

Существуют также различные текстовые форматы, такие как text/html для HTML текста или text/plain для произвольных текстовых данных.

И, конечно, если вы не укажете MIME-тип, Android будет пытаться вывести его для вас.

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

Вы также можете установить и данные и тип вместе, вызывая метод setDataAndType.

Intent также имеет поле компонента, которое идентифицирует целевую активность намерения.

И вы можете установить это поле, если вы знаете, что есть ровно одна активность, которая всегда должна получать это намерение.

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

И мы увидим пример такого кода позже.

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

Intent также имеет поле дополнений Еxtras.

Поля extras хранят дополнительную информацию, связанную с намерением.

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

Например, Intent-класс определяет Еxtras под названием extra_email.

И это дополнение используется для передачи списка получателей при отправке электронной почты.

Как вы можете видеть здесь, этот код создает намерение с действием intent.action_send.

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

И в этом случае значения дополнения включают aporter@cs.umd.edu, ceo@microsoft.com, potus@whitehouse.gov и Моцарт в musician.org.

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

Так, например, существует один метод для хранения строки, другой метод для хранения массива чисел и так далее.

Другое поле намерения называется флаги Flags.

Flags представляют информацию о том, как намерение должно быть обработано.

Некоторые встроенные флаги включают:

Флаг FLAG_ACTIVITY_NO_HISTORY, означает, что когда активность началась, на основе этого намерения, она не должна быть помещена в стек истории.

Другой флаг FLAG_DEBUG_LOG_RESOLUTION говорит Android распечатать дополнительную регистрационную информацию, когда это намерение будет обрабатываться.

И это отличный инструмент для использования, если ваши намерения не запускают активности, которые вы хотите.

Лекция 5. Класс Intent. Часть 2

Давайте поговорим о том, как вы используете намерения для запуска активностей.

Если вы помните, на прошлых уроках я говорил о том, как вы могли программно начать активность, используя методы, такие как startActivity или startActivityForResult.

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

И есть два способа, как Android делает это.

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

Второй способ используется, только если вы явно не устанавливаете целевую активность – Android может неявно определить целевую активность на основе намерения, которое было использовано, и на основе свойств активностей, которые вы установили на вашем устройстве.

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

И это приложение называется HelloWorldWithLogin.

Это приложение включает в себя два вида активности – Login Activiy и Hello Android.

Теперь, когда это приложение запускается, активность Login Activiy является первой активностью, которая запускается.

Login Activiy активность обеспечивает текстовое поле для набора имени пользователя и другое текстовое поле для ввода пароля.

Существует также кнопка, и как только пользователь вводит имя пользователя и пароль, он нажимает кнопку Login.

А затем LoginActivity будет проверять ввод, пароль и имя пользователя, и если активность LoginActivity принимает их, она будет затем запускать активность HelloAndroidActivity, которая будет отображать строку «Hello Android».

Давайте посмотрим на код, чтобы увидеть, как именно это реализовано.

Здесь показан код слушателя, который присоединен к кнопке loginButton и который собирает имя пользователя и пароль, которые пользователь только что ввел.

И затем данный код передает их в метод проверки пароля, называемый checkPassword.

Если проверка пароля возвращает истину, тогда код будет продолжать свое выполнение.

Сначала создается намерение helloAndroidIntent.

И как вы можете видеть, вызов конструктора намерения принимает два параметра – объект контекста и объект класса активности, которая должна быть запущена.

В этом случае используется LoginActivity.this в качестве контекста.

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

А поскольку активность является подклассом контекста, можно прекрасно использовать LoginActivity.this для этого параметра.

Второй параметр является объектом класса, в этом случае HelloAndroid активности.

Этот параметр указывает активность, которая будет запущена вызовом метода startActivity.



Второй способ, чтобы запустить активность – неявная активация.

В этой ситуации, вы не говорите прямо Android, какую активность нужно начать, так что Android должен понять это самостоятельно.

В этом случае Android пытается сопоставить намерение, которое было передано в метод startАctivity или startАctivityForResult, с возможностями активностей, которые находятся на устройстве.

И этот процесс называется разрешением намерения.

Разрешение намерения основывается на двух видах информации.

Во-первых, есть намерение, которое описывает операцию, которую должна выполнить активность.

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

Во время выполнения, когда метод startАctivity вызывается, Android будет пытаться сопоставить намерение с фильтрами намерений, которые Android известны.

При этом Android будет использовать только часть информации намерения, когда Android будет делать это сопоставление.

В частности, он будет смотреть на поле действия, он будет смотреть на данные, включая как URI, так и MIME тип, и он будет смотреть на категорию.

Итак, давайте посмотрим, как приложение указывает фильтры намерений в AndroidManifest.xml файле.

Этот XML фрагмент показывает тэг активности, который заключает в себе тэг фильтра намерений.

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

Например, если активность может набрать телефонный номер, то она должна включать в себя фильтр намерений со стандартным действием intent.action_dial.

Это Java-имя действия, фактическое значение, на самом деле является строкой,

так что вы увидите android.intent.action.Dial, вот значение, которое на самом деле будет записываться в фильтр намерений.

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

Например, активность может указать, что она обрабатывает MIME-тип данных, она может также указать схему, хост и порт URI-адресов данных, которые она обрабатывает.

Активность может далее ограничить формат URI данных, указав его путь, шаблон пути, префикс пути.

И есть немало возможностей здесь.

Так что смотрите документацию для большего количества примеров.

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

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

И давайте посмотрим на пример, который соберет все это вместе.

Приложение Google Maps, которое мы видели раньше, может обрабатывать намерения, которые имеют действие intent.action_view и имеет поле данных со схемой гео.

Давайте посмотрим на AndroidManifest.xml файл приложения Google Maps.

Здесь есть активность с фильтром намерений, который объявляет действие intent.action.VIEW.

И фильтр он имеет схему данных гео.

И на самом деле, это именно то, что приложение MapLocation передает в метод startАctivity.

Возвращаясь к Google Maps, активность также перечисляет две категории:

    сategory.Browsable – это означает, что активность может отвечать на ссылки браузера.

    И category.Default.

В большинстве случаев активности, которые хотят принимать неявные намерения, должны включать category.Default в своих фильтрах намерений.

И, наконец, если более чем один вид активности может принять конкретное намерение, Android сможет разорвать связь несколькими способами.

И один из способов сделать это, просто спросить пользователя, какую активность он хочет, чтобы обработать намерение.

Другая возможность состоит в том, что активность может указать приоритет.

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

Эти приоритетные значения должны быть между -1000 и +1000.

И большие значения означают более высокий приоритет.

Теперь для тех из вас, кто заинтересован узнать больше о фильтрах намерений, я рекомендую вам взять и посмотреть на команду adb dumpsys.

Здесь я открыл окно терминала, и я ввожу команду adb shell dumpsys

package.

Выполнение команды выдаст тонну информации от менеджера пакетов.

Так что я просто захвачу вывод этой команды в текстовый файл.

Давайте запустим команду и откроем этот файл в текстовом редакторе.

Найдем строку гео.

И то, что вы видите здесь, приложение Google Maps на самом деле имеет фильтр намерений для URI со схемой гео.