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

Люди не блуждают по миру бесцельно: большинство из того, что они делают – от просмотра телевизора до написания приложений – имеет за собой какую-то цель или намерение.

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

Оказывается, люди и Android не так уж и различны.

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

  • Что такое намерение и какова его роль в Android;
  • Как использовать намерения для создания и получения контента из других приложений для использования в ваших собственных;
  • Как получать и отвечать на намерение, отправленное другим приложением.

Начало работы

Начните с загрузки стартового проекта для этого урока.

Внутри вы найдете XML разметку и активности, которые содержат шаблонный код для приложения, а также вспомогательный класс для изменения размера растровых изображений и ресурсы (Drawables и Strings), которые вы будете использовать в этом уроке позже.

Если у вас уже открыта Android Studio, нажмите File > New > Import project и выберите скачанный стартовый проект. Если нет, то запустите Android Studio и выберите Open an existing Android Studio project на стартовом экране и выберите скачанный стартовый проект.

Потратьте некоторое время, чтобы ознакомиться с проектом, прежде чем продолжить. TakePictureActivity содержит ImageView, на который вы можете нажать, чтобы сделать снимок с помощью камеры вашего устройства. Когда вы нажмёте кнопку «Сгенерировать мем!», вы передадите путь к файлу растрового изображения, находящегося в ImageView, в EnterTextActivity, где начинается настоящая забава, так как вы можете ввести свой текст, чтобы превратить фотографию в новый вирусный мем!

Создание вашего первого намерения

Соберите и запустите проект. Вы должны увидеть следующее:

В настоящий момент если вы коснётесь ImageView, то ничего не произойдёт!

Добавив следующий код, вы сделаете приложение более интересным.

Откройте TakePictureActivity.java и добавьте следующую константу в начале класса:

private static final int TAKE_PHOTO_REQUEST_CODE = 1;

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

Примечание: в этом уроке предполагается, что вы знакомы с обработкой предупреждений об импорте пакетов и будете явно указывать импорт пакета для добавления. Пакет — это специальный библиотечный модуль, содержащий группу классов, объединённых одним пространством имён. Пакеты импортируются для того, чтобы в будущем не было необходимости писать имя пакета целиком, а лишь указать имя класса. В качестве памятки, если вы не настроили импорт пакетов на лету, вы можете импортировать их, нажимая Alt+Enter, когда курсор находится на предупреждении об импорте.

Добавьте следующий код чуть ниже onClick() вместе с необходимыми импортированными пакетами:

private void takePictureWithCamera() {
  // 1
  Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
 
  // 2
  File imagePath = new File(getFilesDir(), "images");
  File newFile = new File(imagePath, "default_image.jpg");
  if (newFile.exists()) {
    newFile.delete();
  } else {
    newFile.getParentFile().mkdirs();
  }
  selectedPhotoPath = getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", newFile);
 
  // 3
  captureIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, selectedPhotoPath);
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
  } else {
    ClipData clip= ClipData.newUri(getContentResolver(), "A photo", selectedPhotoPath);
    captureIntent.setClipData(clip);
    captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
  }
}

В этом методе много чего происходит, поэтому посмотрим шаг за шагом.

Первый блок кода объявляет объект Intent. Что же такое Intent?

Намерения – это абстрактная концепция работы или функциональности, которая может быть выполнена вашим приложением в будущем. Иными словами, это что-то, что ваше приложение должно сделать. В основном намерения состоят из следующих элементов:

  • Действия (Actions) – это то, чего намерению необходимо достичь, например, набрать номер, открыть ссылку, передать данные. Действие является просто строковой константой.
  • Данные (Data) – это ресурсы, которыми оперирует намерение. Они выражаются как URI объекты в Android. Тип требуемых данных для намерения изменяется в зависимости от действия. Вы ведь не хотите, чтобы ваше намерения для набора номера пыталось получить номер из изображения.

Эта возможность объединять действия и данные позволяет Android точно знать, что намерение собирается делать и с чем оно должно работать. Это так просто!

Вернитесь назад к takePictureWithCamera() и вы увидите, что намерение, которое вы создали, используется действие ACTION_IMAGE_CAPTURE. Вы, наверное, уже догадались, что это намерение сделает для вас фото, которое и нужное генератору мемов!

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

Примечание: Вы можете заметить, что переменная selectedPhotoPath добавляет в строку .fileprovider. Провайдеры файлов – это особый способ предоставления файлов вашему приложению и обеспечения его безопасности и безопасного доступа. Если вы проверите манифест Android, вы увидите, что приложение использует его.

Изучение Extras

Третий блок кода в вашем методе добавляет дополнения (Extra) к вашему намерению.

Что это такое, спросите вы?

Extras – это одна из пар типа «ключ-значение», которая даёт вашему намерению дополнительную информацию. Точно также люди с большей вероятностью будут работать лучше, если они готовы к этому, тоже самое можно сказать о намерениях в Android. Хорошее намерение всегда подготовлено с дополнительными данными, которые ему нужны!

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

Хорошим примером является намерение с действием ACTION_WEB_SEARCH. Это действие принимает пару «ключ-значение», называемую QUERY, которая представляет собой строку запроса, который вы ищете. Ключ в Extras является строковой константой, потому что его имя не должно меняться. Запуская намерение с вышеуказанным действием и связанным с ним дополнением, вы увидите страницу поиска Google с результатами вашего запроса.

Вернитесь назад на строку captureIntent.putExtra(). EXTRA_OUTPUT указывает, где вы должны сохранить фотографию с камеры – в данном случае это расположение URI пустого файла, который вы создали ранее.

Ваше намерение в действии

Теперь у вас есть готовое к работе намерение, а также полное представление того, как выглядит типичное намерение:

Осталось не так много сделать для того, что намерение выполнило свою задачу. Добавьте следующую часть кода в конец метода takePictureWithCamera():

startActivityForResult(captureIntent, TAKE_PHOTO_REQUEST_CODE);

Эта строка отправляет запрос Android на старт активности, которая может выполнить действие, прописанное в намерении: сделать фото и сохранить его. После того, как активность выполнила действие, вам понадобится получить созданное изображение. TAKE_PHOTO_REQUEST_CODE, константа, указанная вами ранее, будет использоваться для идентификации намерения, когда оно вернётся.

Затем добавьте следующий код в onClick() внутри case R.id.picture_imageview перед break:

takePictureWithCamera();

Этот код будет вызывать takePictureWithCamera(), когда вы касаетесь ImageView.

Время проверять плоды вашего труда! Соберите проект и запустите. Коснитесь ImageView, чтобы вызвать камеру:

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

Примечание: если вы запускаете приложение в эмуляторе, вам может потребоваться отредактировать настройки камеры на вашем AVD. Для этого выберите Tools > Android > AVD Manager и нажмите на зелёный карандаш справа на виртуального устройства, которое вы хотите отредактировать. Затем нажмите Show advanced settings в левом нижнем углу окна. В разделе Camera убедитесь, что для всех камер выставлено значение Emulated или Webcam0.

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

Если вы запускаете приложение на физическом устройстве с несколькими приложениями-камерами, вы можете увидеть нечто неожиданное:

Вам будет предложено выбрать, какое приложение будет обрабатывать намерение.

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

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

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

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

Вы можете предотвратить это, проверив результат, чтобы убедиться, что хотя бы одно приложение ответило на это действие, прежде чем пытаться его запустить, или же вы можете заявить, что приложение может быть установлено только на устройствах, у которых есть камера. Для того, чтобы добавить это требование, нужно добавить следующий код в AndroidManifest.xml:

<uses-feature android:name="android.hardware.camera" />

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

Таким образом, у вас есть неявное намерение, чтоб сделать снимок, но нет способа получить доступ к этой фотографии в вашем приложении. Ваш генератор мемов далеко не уйдёт без фотографии!

Добавьте следующий метод чуть ниже takePictureWithCamera() в TakePictureActivity:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
 
  if (requestCode == TAKE_PHOTO_REQUEST_CODE && resultCode == RESULT_OK) {
    // setImageViewWithImage();
  }
}

Вышеуказанный метод выполняется только в том случае, когда метод startActivityForResult() в takePictureWithCamera() завершается и возвращает результат.

Оператор if проверяет возвращённое значение requestCode, которое должно соответствовать константе TAKE_PHOTO_REQUEST_CODE, чтобы убедиться, что это ваше намерение. Также проверяется, чтобы resultCode был равен RESULT_OK. Эта постоянная указывает на успешное выполнение.

Если всё будет хорошо, тогда вы можете предположить, что изображение готово к использованию, поэтому можно вызывать setImageViewWithImage().

Время определить этот метод!

Сначала в верхней части TakePictureActivity добавьте следующую переменную типа Boolean:

private boolean pictureTaken;

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

Затем добавьте следующий код после onActivityResult():

private void setImageViewWithImage() {
  takePictureImageView.post(new Runnable() {
    @Override
    public void run() {
      Bitmap pictureBitmap = BitmapResizer.shrinkBitmap(
        TakePictureActivity.this,
        selectedPhotoPath,
        takePictureImageView.getWidth(),
        takePictureImageView.getHeight()
      );
      takePictureImageView.setImageBitmap(pictureBitmap);
    }
  });

  lookingGoodTextView.setVisibility(View.VISIBLE);
  pictureTaken = true;
}

BitmapResizer – это вспомогательный класс в комплекте со стартовым проектом, чтобы убедиться, что Bitmap, который вы получаете от камеры, масштабируется до нужного размера для экрана вашего устройства. Хотя устройство может масштабировать изображение для вас, изменение размера таким образом более эффективно с точки зрения памяти.

Теперь, когда setImageViewWithImage() готов, раскомментируйте строку, которая вызывает этот метод в onActivityResult():

// setImageViewWithImage();

Соберите проект и запустите. Выберите своё любимое приложения для фото – при появлении запроса – и сделайте ещё одну фотографию.

На этот раз фотография должна масштабироваться и отображаться в ImageView:

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

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

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

Всё ещё в TakePictureActivity добавьте следующие константы в начало класса:

private static final String IMAGE_URI_KEY = "IMAGE_URI";
private static final String BITMAP_WIDTH = "BITMAP_WIDTH";
private static final String BITMAP_HEIGHT = "BITMAP_HEIGHT";

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

Теперь добавьте следующий метод в нижней части TakePictureActivity, добавив при необходимости импорты:

private void moveToNextScreen() {
  if (pictureTaken) {
    Intent nextScreenIntent = new Intent(this, EnterTextActivity.class);
    nextScreenIntent.putExtra(IMAGE_URI_KEY, selectedPhotoPath);
    nextScreenIntent.putExtra(BITMAP_WIDTH, takePictureImageView.getWidth());
    nextScreenIntent.putExtra(BITMAP_HEIGHT, takePictureImageView.getHeight());
 
    startActivity(nextScreenIntent);
  } else {
    Toaster.show(this, R.string.select_a_picture);
  }
}

Здесь вы проверяете pictureTaken, чтобы узнать, сделано ли фото и есть ли в ImageView ваше растровое изображение с камеры. Если растрового изображения нет, тогда на активности появится всплывающее сообщение, в котором говорится, что вы должны сделать фото. Сообщение создаётся в классе Toaster, который делает их создание чуточку проще. Если pictureTaken равен true, то вы создаёте намерение для следующего действия и настраиваете необходимые дополнения, используя константы, которые вы только что объявили.

Затем добавьте вызов метода в onClick() в блок case R.id.enter_text_button перед break:

moveToNextScreen();

Соберите проект и запустите. Коснитесь «Сгенерировать мем!» без предварительно сделанной фотографии, и вы увидите всплывающее сообщение:

Если фотография сделана, то moveToNextScreen() переходит к созданию намерения для активности с вводом текста. Он также прикрепляет в качестве дополнений путь URI для растрового изображения, а также его высоту и ширину. Это пригодится в следующей активности.

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

Это намерение создаётся путём предоставления контекста, из которого было создано намерение (в данном случае this), вместе с классом, который должно запустить намерение (EnterTextActivity.class). Поскольку вы явно указали, как намерение переходит от точки А к точке Б, Android просто исполнит его. Пользователь не имеет контроля над тем, как завершится намерение:

Соберите проект и запустите. Повторите процесс съёмки, но на этот раз коснитесь «Сгенерировать мем!». Ваше явное намерение выполнит действие и запустит следующую активность:

В стартовом проекте эта активность уже создана и объявлена в AndroidManifest.xml, поэтому вам не нужно создавать её самостоятельно.

Обработка намерений

Похоже, намерение сработало. Но где все Extras, которые вы отправили? Они свернули не туда в буфере памяти? Время найти их и заставить работать.

Добавьте следующие константы в начало класса EnterTextActivity:

private static final String IMAGE_URI_KEY = "IMAGE_URI";
private static final String BITMAP_WIDTH = "BITMAP_WIDTH";
private static final String BITMAP_HEIGHT = "BITMAP_HEIGHT";

Это просто тени тех констант, которые вы создали в предыдущей активности.

Затем добавьте следующий код в конец метода onCreate():

pictureUri = getIntent().getParcelableExtra(IMAGE_URI_KEY);
 
int bitmapWidth = getIntent().getIntExtra(BITMAP_WIDTH, 100);
int bitmapHeight = getIntent().getIntExtra(BITMAP_HEIGHT, 100);
 
Bitmap selectedImageBitmap = BitmapResizer.shrinkBitmap(this, pictureUri,
bitmapWidth, bitmapHeight);
selectedPicture.setImageBitmap(selectedImageBitmap);

Когда вы создаёте активность, вы присваиваете URI, переданный из предыдущей активности, в pictureUri путём доступа к намерению через метод getIntent(). Когда у вас есть доступ к намерению, вы можете получить доступ к своим Extras.

Поскольку переменные и объекты приходят в разных формах, у вас есть несколько методов доступа к ним. Для доступа к URI выше, например, вам необходимо использовать getParcelableExtra(). Другие дополнения существуют для других переменных, таких как строки и примитивные типы данных.

getIntExtra(), аналогично другим методам, возвращающим примитивы, также позволяет вам определить значение по умолчанию. Они используются, когда значение не указано ключ отсутствует в Extras.

После того, как вы извлекли необходимые дополнения, создайте растровое изображение из URI с помощью значений размера BITMAP_WIDTH и BITMAP_HEIGHT, которые вы передали. Наконец, вы устанавливаете источник изображения ImageView в растровое изображение для отображения фотографии.

В дополнение к отображению ImageView этот экран содержит также два вида EditText, в которых пользователь может ввести свой текст мема. Стартовый проект делает за вас тяжёлую работу, принимая текст из этих компонент и комбинируя его с фотографией.

Единственное, что вам нужно сделать – это очистить onClick(). Добавьте следующую строку в блок case R.id.write_text_to_image_button перед break:

createMeme();

Барабанная дробь. Соберите проект и запустите. Повторите обычные шаги, чтобы сделать снимок, а затем введите свой невероятно остроумный текст мема на втором экране и нажмите «Сгенерировать мем!»:

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

Передача намерения

Было бы неплохо сохранить ваш блестящий новый мем, чтобы вы могли поделиться им с миром. Он не станет вирусом сам по себе.

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

Добавьте следующий код в saveImageToGallery(), чуть ниже блока try перед вторым вызовом Toaster.show():

Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(imageFile));
sendBroadcast(mediaScanIntent);

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

Действие ACTION_MEDIA_SCANNER_SCAN_FILE также требует, чтобы намерение имело прикрепленные данные в форме URI, которые поступают из объекта File, в котором хранится Bitmap.

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

Теперь добавьте следующий код в onClick(), внутри блока case R.id.save_image_button перед break:

askForPermissions();

Когда пользователь нажимает «Сохранить изображение», вышеуказанный код проверяет разрешение WRITE_EXTERNAL_STORAGE. Если он не предоставляется на Android Marshmallow и выше, метод вежливо попросит пользователя предоставить его. В противном случае, если вам разрешено писать на внешнее хранилище, он просто передаёт управление методу saveImageToGallery().

Код в saveImageToGallery() выполняет некоторую обработку ошибок и, если всё хорошо, стартует с намерения.

Соберите проект и запустите. Сделайте фото, добавьте какой-нибудь потрясающий текст для мема, нажмите «Сгенерировать мем!», а затем нажмите «Сохранить изображение», как только ваш мем будет готов.

Теперь закройте приложение и откройте приложение «Фото». Если вы используете эмулятор, откройте приложение  «Галерея». Там вы увидите своё новое изображение во всей красе.

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

Фильтрация намерений

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

Откройте AndroidManifest.xml и в первой активности вы увидите следующее:

<activity
  android:name=".TakePictureActivity"
  android:label="@string/app_name"
  android:screenOrientation="portrait">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
 
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>

Ключевой момент здесь это Intent Filter. Фильтр намерений позволяет частям вашего приложения реагировать на неявные намерения.

Они ведут себя как баннер когда Android пытается выполнить неявное намерение, отправленное другим приложением. Приложение может иметь несколько фильтров намерений, надеясь, что его фильтр намерений сможет выполнить то, что нужно Android:

Это похоже на онлайн-знакомства для намерений и приложений.

Чтобы убедить, что это подходящее приложение для намерения, фильтр намерений предоставляет следующие три вещи:

Действие намерения: действие, которое приложение может выполнить. Это похоже на то, как приложение камеры выполняет действие ACTION_IMAGE_CAPTURE для вашего приложения.

Данные намерения: тип данных, которые может принять намерение. Он варьируется от конкретных путей к файлам до портов , до типов MIME, таких как изображения и видео. Вы можете установить один или несколько атрибутов, чтобы контролировать, насколько строги или мягки вы с данными из намерения, которое получено вашим приложением.

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

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

Добавьте следующий код непосредственно под первым фильтром намерений в файле AndroidManifest.xml:

<intent-filter>
  <action android:name="android.intent.action.SEND" />
  <category android:name="android.intent.category.DEFAULT" />
  <data android:mimeType="@string/image_mime_type" />
</intent-filter>

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

Теперь откройте TakePictureActivity.java и добавьте следующий код в конец класса:

private void checkReceivedIntent() {
  Intent imageRecievedIntent = getIntent();
  String intentAction = imageRecievedIntent.getAction();
  String intentType = imageRecievedIntent.getType();
 
  if (Intent.ACTION_SEND.equals(intentAction) && intentType != null) {
    if (intentType.startsWith(MIME_TYPE_IMAGE)) {
      selectedPhotoPath = imageRecievedIntent.getParcelableExtra(Intent.EXTRA_STREAM);
      setImageViewWithImage();
    }
  }
}

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

Если всё совпадает, то вы получите URI изображения, запросив URI для Bitmap, используя вспомогательный метод, включенный в стартовый проект, и, наконец, запросите у ImageView отобразить извлечённый Bitmap.

Затем добавьте следующую строку в конец метода onCreate():

checkReceivedIntent();

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

Соберите проект и запустите. Затем вернитесь на главный экран и перейдите в приложение «Фото» или «Галерея» если вы используете эмулятор. Выберите любую фотографию и коснитесь кнопки «Отправить». Вы должны увидеть генератор мемов среди представленных вариантов:

Генератор мемов готов и ждёт, чтобы получить вашу фотографию! Выберите генератор мемов и посмотрите, что произойдёт — генератор мемов запускается с выбранной фотографией, уже загруженной в ImageView.

Ваше приложение теперь получает намерения как босс!

Куда пойти дальше?

Намерения — один из фундаментальных блоков Android. Большая часть открытости и связи, которой гордится Android, просто не будет возможна без них. Изучите как пользоваться намерениями и тогда вы обретёте могущественного союзника.

Если вы хотите узнать больше о намерениях и фильтрах намерений, то загляните в документацию Google.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *