Намерения (Intent)

Намерения

  • Это механизм для описания одной операции - выбрать фотографию, отправить письмо, сделать звонок, запустить браузер и перейти по указанному адресу.
  • В Android-приложениях многие операции работают через намерения.
  • Наиболее распространённый сценарий использования намерения - запуск другой активности в своём приложении.
  • Также можно использовать для объявления о запуске активности или сервиса, направленных на выполнение каких-либо действий
  • или для передачи уведомлений о том, что произошло некое событие (или действие).

Намерения

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

Намерения

Intent intent = new Intent(HelloWorld.this, AboutActivity.class);
startActivity(intent);				    
				    
  • В намерении мы явно указали имя класса активности во втором параметре.
  • Данный класс у нас прописан в манифесте, и система, просматривая манифест, запустит нужную активность.
  • Первый параметр – это Context. Активность является подклассом Context, поэтому мы можем использовать её как HelloWorld.this, или укороченную запись this.

Передача параметров

// У первой активности
ArrayList<File> fileList = new ArrayList<File>();
 
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("FILES_LIST", fileList);
startActivity(intent);

// У второй активности
ArrayList<File> filelist = 
    (ArrayList<File>)getIntent().getSerializableExtra("FILES_LIST");				    
				    

Передача параметров

  • При переходе на другую активность мы можем указать какие-то данные
  • принимающая активность должна уметь обработать их.
  • Для этих целей существуют методы типа putXXX().
  • Например, для передачи списка файлов из одной активности в другую.
  • При работе с действиями, возвращающими данные, нельзя использовать метод startActivity(), поскольку он не возвращает результат.
  • Если вы хотите вернуть данные, то можете использовать метод startActivityForResult(), приспособленный для работы с обратными вызовами.

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

  • Существует также неявный вызов активности.
  • В этом случае при создании намерения мы используем не имя класса, а указываем параметры action, data, category с определёнными значениями.
  • если указали в параметрах адрес веб-страницы, то скорее всего хотим запустить браузер
  • Комбинация значений в параметрах определяют цель, которую мы хотим достичь.
  • Это может быть открытие ссылки, отправка письма, набор телефонного номера и т.п.

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

  • можем прописать в своей активности в фильтрах намерений (Intent Filter) набор тех же параметров: action, data, category.
  • тогда у пользователя может запуститься не только стандартный браузер, но и наша программа
  • если параметры намерения совпадают с условиями нашего фильтра, то наше приложение (активность) будет вызвано.
  • Система сканирует активности всех установленных приложений, и если находится несколько подходящих активностей, то Android предоставляет пользователю выбор, какой именно программой следует воспользоваться.
  • Если найдётся только одна подходящая активность, то, естественно, никакого диалога для выбора не будет, и активность запустится автоматически.

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

  • Создавая новое неявное намерение для передачи в метод startActivity(), необходимо назначить действие, которое должно выполниться
  • также при желании указать вспомогательный путь URI к тем данным, что нужно обработать.
  • Можно передать дополнительные данные в другую активность, используя параметр намерения extras.
  • При применении этого намерения для запуска активности система во время работы приложения сама найдёт класс компонента, который лучше всего подходит для заданного действия, учитывая указанный тип данных.
  • Это значит, что вы можете создавать проекты, используя возможности других приложений и не зная при этом, как они называются и какую функциональность предоставляют.

Проверка наличия приложения

  • следует помнить, что нет никакой гарантии, что приложение, способное обработать ваше намерение, будет установлено и доступно на устройстве.
  • Например, если приложение установлено на планшете без телефонного модуля.
  • Чтобы узнать, будет ли запущена активность для вашего намерения, можно отправить запрос Менеджеру пакетов при помощи метода resolveActivity().
  • Желательно делать такую проверку во всех примерах

Неявные намерения. Пример.

Простой пример создания намерения с предопределённым действием ACTION_VIEW для запуска браузера и перехода на нужный адрес:
Uri address = Uri.parse("https://google.com");
Intent openLinkIntent = new Intent(Intent.ACTION_VIEW, address);

if (openLinkIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(openlinkIntent);
} else {
    Log.d("Intent", "Не получается обработать намерение!");
}
				    

Объект Intent

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

Поля объекта Intent

  • Имя компонента - имя, который должен обработать намерение.
  • Используется объект ComponentName, который является комбинацией полного имени класса целевого компонента (например, "MainActivity")
  • и набора имени пакета в файле манифеста приложения, где компонент постоянно находится (например, "com.samples.yourproject")
  • Составляющее имя устанавливается методами setComponent(), setClass() или setClassName() и читается методом getComponent()

Поля объекта Intent

  • Действие - определяет действие, которое будет выполнено
  • Класс Intent содержит множество констант действия
  • Название метода определяет ряд параметров и возвращаемое значение.
  • можете также определить собственные действия для активизации активности.
  • В этом случае вы должны включать имя пакета приложения в качестве префикса, например com.samples.yourproject.CUSTOM_ACTiON.
  • Действие в объекте Intent устанавливается в методе setAction() и читается методом getAction()

Поля объекта Intent

  • Данные - это URI данных и тип MIME для этих данных. Разные активности соединены с разными видами спецификаций данных.
  • Категория - строка, содержащая дополнительную информацию о виде компонента
  • В объект Intent можно поместить любое количество описаний категорий.
  • Класс Intent определяет несколько констант CATEGORY, например, CATEGORY_BROWSABLE

Поля объекта Intent

  • Дополнения - пары ключ-значения для дополнительной информации, которую нужно поставить компоненту, обращающемуся с намерением.
  • Например, действие ACTION_TIMEZONE_CHANGED имеет дополнение time-zone, которое идентифицирует новый часовой пояс
  • ACTION_HEADSET_PLUG имеет дополнение state, указывающее, включены ли наушники или отключены
  • Объект Intent имеет ряд методов put...() для вставки различных типов дополнительных данных и подобного набора методов get...() для чтения данных.
  • Дополнения устанавливаются и читаются как объекты Bundle с использованием методов putExtras() и getExtras()

Поля объекта Intent

  • Флаги - указывают системе, как запускать активность
  • например, какому заданию должна принадлежать активность
  • как обработать это после того, как активность запустили
  • например, принадлежит ли она списку недавних активностей
  • Все флаги определены в классе Intent.

Константы действия

  • ACTION_ANSWER — Открывает активность, которая связана с входящими звонками. Это действие обрабатывается стандартным экраном для приёма звонков;
  • ACTION_CALL — инициализирует обращение по телефону;
  • ACTION_DELETE — Запускает активность, с помощью которой можно удалить данные, указанные в пути URI внутри намерения;
  • ACTION_EDIT — Отображает данные для редактирования пользователем
  • ACTION_INSERT — Открывает активность для вставки в Курсор (Cursor) нового элемента, указанного с помощью пути URI. Дочерняя активность, вызванная с этим действием, должна вернуть URI, ссылающийся на вставленный элемент

Константы действия

  • ACTION_HEADSET_PLUG - Подключение наушников
  • ACTION_MAIN — Запускается как начальная активность задания
  • ACTION_SEARCH — Запускает активность для выполнения поиска. Поисковый запрос хранится в виде строки в дополнительном параметре намерения по ключу SearchManager.QUERY
  • ACTION_SENDTO — Открывает активность для отправки сообщений контакту, указанному в пути URI, который передаётся через намерение

Константы категорий

  • CATEGORY_BROWSABLE — активность может быть безопасно вызвана браузером, чтобы отобразить ссылочные данные, например, изображение или почтовое сообщение
  • CATEGORY_HOME — активность отображает Home Screen, первый экран, который пользователь видит после включения устройства и загрузки системы, или когда нажимает клавишу HOME
  • CATEGORY_LAUNCHER — активность может быть начальной деятельностью задания из списка приложений в группе Application Launcher устройства

Фильтры намерений и запуск заданий

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

Фильтры намерений и запуск заданий

<activity 
    android:name=".HelloWorldActivity" 
    android:label="@string/app_name"> 
    <intent-filter> 
        <action android:name="android.intent.action.MAIN" 
        <category android:name="android.intent.category.LAUNCHER" 
    </intent-filter> 
</activity> 				    
				    
  • в любом приложении есть главная активность, которая устанавливается как точка входа для задания
  • Фильтр такого вида в элементе <action> помечает активность, как запускаемую по умолчанию.
  • Пользователям предоставляется возможность запускать задание и возвращаться к этому заданию в любое время после того, как оно было запущено

Фильтры намерений и запуск заданий

  • action - Использует атрибут android:name, чтобы задать название действия, которое будет обслуживаться. Каждый фильтр намерений должен иметь один (и только один) тег action.
  • Действия должны быть представлены в виде уникальных строк, которые сами себя описывают.
  • Рекомендуется выбирать названия, основываясь на соглашении об именовании пакетов в Java.
  • сategory - Использует атрибут android:name, чтобы указать, при каких обстоятельствах должно обслуживаться действие.
  • Каждый тег intent-filter способен содержать несколько тегов category.
  • можете задать собственные категории или же брать стандартные значения, предоставляемые системой

Категории

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

Категории

  • DEFAULT - Установите эту категорию, чтобы сделать компонент обработчиком по умолчанию для действия, выполняемого с указанным типом данных внутри Фильтра намерений. Это необходимо и для Активностей, которые запускаются с помощью явных Намерений
  • GADGET - Наличие этой категории указывает на то, что данная активность может запускаться внутри другой активности.
  • HOME - Устанавливая эту категорию и не указывая при этом действия, вы создаете альтернативу для стандартного домашнего экрана.
  • LAUNCHER - Используя эту категорию, вы помещаете Активность в окно для запуска приложений.

data фильтра

  • data - Этот тег дает возможность указать тип данных, с которым может взаимодействовать ваш компонент.
  • При необходимости можно задать несколько тегов data.
  • Чтобы указать, какие именно данные поддерживает ваш компонент, используйте сочетание следующих атрибутов
  • android:host — задаёт доступное имя удалённого сервера (например, google.com);
  • android:path — задает доступные значения для пути URI (например, /transport/boats/);
  • android:port — указывает доступные порты для заданного сервера;

Принцип работы фильтров намерений

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

Принцип работы фильтров намерений

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

Принцип работы фильтров намерений

  • Наконец, каждая часть пути URI из Намерения сравнивается с тегом data Фильтра намерений.
  • Если в Фильтре указаны схема (протокол), сервер/принадлежность, путь или тип MIME, все эти значения проверяются на соответствие пути URI из Намерения.
  • При любом несовпадении Фильтр будет удален из списка.
  • Если в Фильтре намерений не указано ни одного параметра data, его действие будет распространяться на любые данные.
  • Когда вы неявным образом запускаете Активность и вышеописанный процесс возвращает более одного совпадения, пользователю выводится список со всеми вариантами

ACTION_PICK

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

ACTION_PICK

// Показываем все программы для запуска
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("*/*");
startActivityForResult(intent, 1);				    
				    
  • диалоговое окно со списком всех возможных программ, которые могут запустить активность с данными, так как мы не указываем конкретный тип (setType("*/*"))
  • Если мы укажем конкретный тип данных, которые нас интересует, то список программ существенно сузится. Например, если указать intent.setType("image/*");
  • то можем увидеть только системную программу Галерея для просмотра картинок

ACTION_SEND

  • Используйте метод setType(), чтобы указать тип MIME для передаваемых данных.
  • Эти данные должны храниться в параметре намерения extras с ключами EXTRA_TEXT или EXTRA_STREAM, в зависимости от типа.
  • В случае с электронной почтой стандартное приложение в Android также принимает дополнительные параметры по ключам EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC и EXTRA_SUBJECT.
  • Если есть установленное приложение с фильтром, который соответствует ACTION_SEND и MIME-типу text/plain, система Android запустит его
  • Если ваша активность хочет обрабатывать подобные намерения, то она должна содержать следующие данные:
<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>				    
				    

Выбор файла

public class PickFileActivity extends Activity {
    TextView textView;
 
    private static final int PICKFILE_RESULT_CODE = 1;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
      
        Button buttonPick = findViewById(R.id.buttonpick);
        textView = findViewById(R.id.textView);
      
        buttonPick.setOnClickListener(new Button.OnClickListener(){
        @Override
        public void onClick(View arg0) {
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.setType("file/*");
            startActivityForResult(intent,PICKFILE_RESULT_CODE);
        }});
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch(requestCode){
            case PICKFILE_RESULT_CODE:
                if(resultCode == RESULT_OK){
                    String FilePath = data.getData().getPath();
                    textView.setText(FilePath);
                }
                break;
        }
    }
}