Каждый Android-разработчик сталкивался с необходимостью передать данные из одной Activity в другую. Эта тривиальная задача зачастую вынуждает нас писать не самый элегантный код.  Наконец, в 2020 году Google представила решение старой проблемы — Activity Result API. Это мощный инструмент для обмена данными между активностями и запроса runtime permissions.  В данной статье мы разберёмся, как использовать новый API и какими преимуществами он обладает.  Роберт Мартин в книге “Чистый код” отмечает важность переиспользования кода — принцип DRY или Don’t repeat yourself, а также призывает проектировать компактные функции, которые выполняют лишь единственную операцию.  Проблема onActivityResult() в том, что при его использовании соблюдение подобных рекомендаций становится практически невозможным. Убедимся в этом на примере простого экрана, который запрашивает доступ к камере, делает фото и открывает второй экран — SecondActivity. Пусть в SecondActivity мы передаём строку, а назад получаем целое значение. Очевидно, что метод onActivityResult() нарушает принцип единственной ответственности, ведь он отвечает и за обработку результата фотографирования и за получение данных от второй Activity. Да и выглядит этот метод уже довольно запутанно, хоть мы и рассмотрели простой пример и опустили часть деталей. Кроме того, если в приложении появится другой экран со схожей функциональностью, мы не сможем переиспользовать этот код и будем вынуждены его дублировать. Новый API доступен начиная с AndroidX Activity 1.2.0-alpha02 и Fragment 1.3.0-alpha02, поэтому добавим актуальные версии соответствующих зависимостей в build.gradle: Применение Activity Result состоит из трех шагов: Контракт — это класс, реализующий интерфейс ActivityResultContract<I,O>. Где I определяет тип входных данных, необходимых для запуска Activity, а O — тип возвращаемого результата.  Для типовых задач можно воспользоваться реализациями “из коробки”: PickContact, TakePicture, RequestPermission и другими. Полный список доступен тут. При создании контракта мы обязаны реализовать два его метода:  createIntent() — принимает входные данные и создает интент, который будет в дальнейшем запущен вызовом launch() parseResult() — отвечает за возврат результата, обработку resultCode и парсинг данных Ещё один метод — getSynchronousResult() — можно переопределить в случае необходимости. Он позволяет сразу же, без запуска Activity, вернуть результат, например, если  получены невалидные входные данные. Если подобное поведение не требуется, метод по умолчанию возвращает null.  Ниже представлен пример контракта, который принимает строку и запускает SecondActivity, ожидая от неё целое число: Следующий этап — регистрация контракта в активности или фрагменте с помощью вызова registerForActivityResult(). В параметры необходимо передать ActivityResultContract и ActivityResultCallback. Коллбек сработает при получении результата.  Регистрация контракта не запускает новую Activity, а лишь возвращает специальный объект ActivityResultLauncher, который нам понадобится далее.  Для запуска Activity остаётся вызвать launch() на объекте ActivityResultLauncher, который мы получили на предыдущем этапе. Отметим несколько неочевидных моментов, которые необходимо учитывать: Регистрировать контракты можно в любой момент жизненного цикла активности или фрагмента, но вот запустить его до перехода в состояние CREATED нельзя. Общепринятый подход — регистрация контрактов как полей класса. Не рекомендуется вызывать registerForActivityResult() внутри операторов if и when. Дело в том, что во время ожидания результата процесс приложения может быть уничтожен системой (например, при открытии камеры, которая требовательна к оперативной памяти). И если при восстановлении процесса мы не зарегистрируем контракт заново, результат будет утерян. Если запустить неявный интент, а операционная система не сможет найти подходящую Activity, выбрасывается исключение ActivityNotFoundException: “No Activity found to handle Intent”. Чтобы избежать такой ситуации, необходимо перед вызовом launch() или в методе getSynchronousResult() выполнить проверку resolveActivity() c помощью  PackageManager. Другим полезным применением Activity Result API является запрос разрешений. Теперь вместо вызовов checkSelfPermission(), requestPermissions() и onRequestPermissionsResult(), стало доступно лаконичное и удобное решение — контракты RequestPermission и RequestMultiplePermissions.  Первый служит для запроса одного разрешения, а второй — сразу нескольких. В колбеке RequestPermission возвращает true, если доступ получен, и false в противном случае. RequestMultiplePermissions вернёт Map, где ключ — это название запрошенного разрешения, а значение — результат запроса. В реальной жизни запрос разрешений выглядит несколько сложнее. В гайдлайнах Google мы видим следующую диаграмму: Зачастую разработчики забывают о следующих нюансах при работе с runtime permissions: Если пользователь ранее уже отклонял наш запрос, рекомендуется дополнительно объяснить, зачем приложению понадобилось данное разрешение (пункт 5a) При отклонении запроса на разрешение (пункт 8b), стоит не только ограничить функциональность приложения, но и учесть случай, если пользователь поставил галочку “Don't ask again” Обнаружить эти граничные ситуации можно при помощи вызова метода shouldShowRequestPermissionRationale(). Если он возвращает true перед запросом разрешения, то стоит рассказать пользователю, как приложение будет использовать разрешение. Если разрешение не выдано и shouldShowRequestPermissionRationale() возвращает false — была выбрана опция “Don't ask again”, тогда стоит попросить пользователя зайти в настройки и предоставить разрешение вручную.  Реализуем запрос на доступ к камере согласно рассмотренной схеме:  Применим знания о новом API на практике и перепишем с их помощью экран из первого примера. В результате мы получим довольно компактный, легко читаемый и масштабируемый код: Мы увидели недостатки обмена данными через onActivityResult(), узнали о преимуществах Activity Result API и научились использовать его на практике.   Новый API полностью стабилен, в то время как привычные onRequestPermissionsResult(), onActivityResult() и startActivityForResult() стали Deprecated. Самое время вносить изменения в свои проекты!  Демо-приложение с различными примерами использования Activty Result API, в том числе работу с runtime permissions, можно найти в моем Github репозитории.  Android Developer