Предположим, вы используете приложение для обмена сообщениями, и друг прислал вам интересную ссылку. Тогда есть несколько вещей, которые вы можете сделать с ним:
- открыть его в браузере
- поделиться им с другим человеком
- возможно сохранить его в приложении заметок
- ...
Если вы воспользуетесь ссылкой как «данные, которые вы просматриваете в настоящее время», было бы хорошо, если бы мессенджер предложил вам выбрать соответствующее действие из пакета. альтернативных действий, которые в настоящее время доступны на вашем устройстве.
С Intent.CATEGORY_ALTERNATIVE
и Menu.addIntentOptions()
, платформа имеет способ для приложения, которое является первоначальным «владельцем» некоторого типа данных, предлагать пользователю доступ к дальнейшим действиям. Эти действия могут быть реализованы любым приложением, которое работает на устройстве и которое объявило о своей способности обрабатывать этот указанный тип данных c с помощью записи в Manifest.xml
, более конкретно в теге <intent-filter>
.
Давайте рассмотрим очень простой - если не очень реалистичный c - пример:
Мое приложение имеет значение String
, которое оно отображает для пользователей. Альтернативными действиями могут быть
- парсинг
String
на основе некоторого регулярного выражения - сортировка букв
String
- , преобразующих
String
, например, в прописные буквы - ...
Мое приложение будет иметь Activity
или Fragment
переопределение onCreateOptionsMenu()
следующим образом (фрагмент кода для Fragment
)
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.home_menu, menu);
// Create an Intent that describes the requirements to fulfill, to be included
// in our menu. The offering app must include a category value of Intent.CATEGORY_ALTERNATIVE.
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_TEXT, "Lorem ipsum");
intent.setType("text/plain");
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
// Search and populate the menu with acceptable offering applications.
menu.addIntentOptions(
R.id.intent_group, // Menu group to which new items will be added
0, // Unique item ID (none)
0, // Order for the items (none)
this.getActivity().getComponentName(), // The current activity name
null, // Specific items to place first (none)
intent, // Intent created above that describes our requirements
0, // Additional flags to control items (none)
null); // Array of MenuItems that correlate to specific items (none)
}
Activity
s, которые могут обрабатывать данные String
, объявят IntentFilter
как дочерний тег своего тега в Manifest.xml
:
<activity android:name=".ToUpperCaseActivity">
<intent-filter android:label="@string/label_action_text_to_uppercase">
<action android:name="de.ddvsidedown.alternativeoptionsapp.action.ALL_CAPS" />
<category android:name="android.intent.category.ALTERNATIVE" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
или
<activity android:name=".SortActivity">
<intent-filter android:label="@string/label_action_sort_text">
<action android:name="de.ddvsidedown.alternativeoptionsapp.action.SORT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Тогда мое приложение покажет следующее всплывающее меню, когда пользователь нажмет на значок переполнения ...
. .. и среда выполнения перейдет непосредственно к выбранному Activity
. Там текст можно получить следующим образом:
if(getIntent().hasExtra(Intent.EXTRA_TEXT)) {
char[] ca = getIntent().getCharSequenceExtra(Intent.EXTRA_TEXT).toString().toCharArray();
Arrays.sort(ca);
String message = buildString(ca);
Log.d(TAG, "onCreate: " + message);
TextView textView = findViewById(R.id.tvResult);
textView.setText(message);
}
Обратите внимание, что точный код для извлечения данных зависит от типа данных, как и в случае с «обычными» Intent
s без <category>
пометить вообще или с помощью <category android:name="android.intent.category.DEFAULT" />
в <intent-filter>
.
как это работает, если нам нужно включить CATEGORY_DEFAULT для того, чтобы действие получало неявные намерения
Вам нужно <category android:name="android.intent.category.DEFAULT"/>
в <intent-filter>
из Activity
, если вы хотите, чтобы оно появилось в диалоге выбора. Кстати, Activity
может иметь несколько <intent-filter>
тегов
Давайте изменим пример: мое приложение также имеет "SHARE" Button
. При щелчке выполняется следующий фрагмент кода:
/**
* Will only work with <category android:name="android.intent.category.DEFAULT" />
*/
private void shareText() {
// Create the text message with a string
Intent sendIntent = new Intent();
//sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "Lorem ipsum");
sendIntent.setType("text/plain");
// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivity(sendIntent);
}
}
Во время выполнения пользователю будет показан диалог выбора. Каждый Activity
с <intent-filter>
с <category android:name="android.intent.category.DEFAULT"/>
будет отображаться с названием приложения и значком запуска приложения. (Хотя можно иметь два Activity
с CATEGORY_DEFAULT
в одном приложении, очевидно, что это выглядит не очень хорошо - возможно, можно настроить текст и / или значок, но это определенно выходит за рамки этого вопроса)
Если я закомментирую ACTION_SEND
, тогда диалог выбора будет иметь заголовок «Выполнить действие, используя», тогда как если я установлю ACTION_SEND
, заголовок будет «Поделиться с».
как система [...] принимает решение об обработке многих приложений с «альтернативной» категорией, особенно без знания имени действия
Мое приложение настраивает Intent
, устанавливая (или опуская) действие, категории, а также тип данных. Время выполнения всегда выбирает Activity
s, которые соответствуют всем требованиям моего Intent
. Это означает, что другой Activity
может предложить обрабатывать тип данных "text / *" вместо просто "text / plain", но если он предлагает только "image / *", то он не будет показан пользователю.