На этой странице рассказывается, как настроить среду и создать подсказки в приложении.
Примечание. В Android Studio 3.2 и более поздних версиях есть дополнительные инструменты и функции, которые могут помочь вам в разработке фрагментов.
- Инструмент рефакторинга AndroidX. Требуется, если вы работаете над проектом, в котором используются библиотеки AndroidX.
- Проверка фрагментов на наличие ошибок: выявление распространенных ошибок при создании фрагментов.
- Шаблон
SliceProvider: обрабатывает шаблонный код при созданииSliceProvider.
Как скачать и установить Slice Viewer
Скачайте последнюю версию APK-файла Slice Viewer, чтобы протестировать фрагменты без реализации API SliceView.
Если ADB не настроен должным образом в вашей среде, ознакомьтесь с руководством по ADB.
Установите Slice Viewer на устройство, выполнив следующую команду в том же каталоге, где находится скачанный файл slice-viewer.apk:
adb install -r -t slice-viewer.apk
Как запустить Slice Viewer
Запустить Slice Viewer можно из проекта Android Studio или из командной строки.
Запустите Slice Viewer из проекта Android Studio.
- В проекте выберите Run (Запустить) > Edit Configurations (Изменить конфигурации).
- В левом верхнем углу нажмите на зеленый значок плюса.
Выберите Приложение для Android.

В поле названия введите slice.
В раскрывающемся списке Модуль выберите модуль приложения.
В разделе Launch Options (Параметры запуска) в раскрывающемся списке Launch (Запуск) выберите URL.
В поле URL введите
slice-<your slice URI>.Пример:
slice-content://com.example.your.sliceuri
Нажмите ОК.
Как запустить Slice Viewer с помощью ADB (командной строки)
Запустите приложение из Android Studio:
adb install -t -r <yourapp>.apk
Чтобы посмотреть срез, выполните следующую команду:
adb shell am start -a android.intent.action.VIEW -d slice-<your slice URI>

Slice Viewer с одной подсказкой Wi-Fi
Просмотр всех фрагментов в одном месте
Помимо запуска одного фрагмента, вы можете просматривать постоянный список своих фрагментов.
- Используйте строку поиска, чтобы вручную найти фрагменты по URI (например,
content://com.example.android.app/hello). Каждый раз, когда вы выполняете поиск, фрагмент добавляется в список. - Каждый раз, когда вы запускаете Slice Viewer с URI фрагмента, этот фрагмент добавляется в список.
- Чтобы удалить фрагмент из списка, проведите по нему пальцем.
- Нажмите на URI фрагмента, чтобы открыть страницу, содержащую только этот фрагмент. Это дает тот же эффект, что и запуск Slice Viewer с URI фрагмента.

Slice Viewer со списком фрагментов
Как посмотреть фрагмент в разных режимах
Приложение, в котором показывается фрагмент, может изменять SliceView#mode во время выполнения. Убедитесь, что фрагмент выглядит правильно в каждом режиме.
Чтобы изменить режим, нажмите на значок меню в правом верхнем углу страницы.

Окно просмотра Single Slice в режиме "small"
Как создать первый фрагмент
Чтобы создать фрагмент, откройте проект Android Studio, нажмите правой кнопкой мыши на пакет src и выберите New... > Other (Другое) > Slice Provider (Поставщик фрагментов). Будет создан класс, расширяющий SliceProvider, в файл AndroidManifest.xml будет добавлена запись о поставщике, а в файл build.gradle – необходимые зависимости Slice.
Изменения в AndroidManifest.xml показаны ниже:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.app"> ... <application> ... <provider android:name="MySliceProvider" android:authorities="com.example.android.app" android:exported="true" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.app.slice.category.SLICE" /> </intent-filter> </provider> ... </application> </manifest>
В файл build.gradle будут добавлены следующие зависимости:
Kotlin
dependencies { // ... implementation "androidx.slice:slice-builders-ktx:(latest version)" // ... }
Java
dependencies { // ... implementation "androidx.slice:slice-builders:(latest version)" // ... }
У каждого фрагмента есть связанный с ним URI. Когда на платформе нужно показать фрагмент, она отправляет вашему приложению запрос на связывание с этим URI. Приложение обрабатывает этот запрос и динамически создает фрагмент с помощью метода onBindSlice. Затем поверхность может отобразить фрагмент, когда это необходимо.
Ниже приведен пример метода onBindSlice, который проверяет путь URI /hello и возвращает фрагмент Hello World.
Kotlin
override fun onBindSlice(sliceUri: Uri): Slice? { val activityAction = createActivityAction() return if (sliceUri.path == "/hello") { list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = activityAction title = "Hello World." } } } else { list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = activityAction title = "URI not recognized." } } } }
Java
@Override public Slice onBindSlice(Uri sliceUri) { if (getContext() == null) { return null; } SliceAction activityAction = createActivityAction(); ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY); // Create parent ListBuilder. if ("/hello".equals(sliceUri.getPath())) { listBuilder.addRow(new ListBuilder.RowBuilder() .setTitle("Hello World") .setPrimaryAction(activityAction) ); } else { listBuilder.addRow(new ListBuilder.RowBuilder() .setTitle("URI not recognized") .setPrimaryAction(activityAction) ); } return listBuilder.build(); }
Используйте конфигурацию запуска slice, созданную в разделе Slice Viewer выше, передав URI фрагмента (например, slice-content://com.android.example.slicesample/hello) фрагмента Hello World, чтобы посмотреть его в Slice Viewer.

Интерактивные фрагменты
Как и в случае с уведомлениями, вы можете обрабатывать клики в пределах фрагмента, прикрепляя объекты PendingIntent, которые активируются при взаимодействии с пользователем. В примере ниже запускается Activity, который может получать и обрабатывать эти намерения:
Kotlin
fun createSlice(sliceUri: Uri): Slice { val activityAction = createActivityAction() return list(context, sliceUri, INFINITY) { row { title = "Perform action in app" primaryAction = activityAction } } } fun createActivityAction(): SliceAction { val intent = Intent(context, MainActivity::class.java) return SliceAction.create( PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), 0), IconCompat.createWithResource(context, R.drawable.ic_home), ListBuilder.ICON_IMAGE, "Enter app" ) }
Java
public Slice createSlice(Uri sliceUri) { if (getContext() == null) { return null; } SliceAction activityAction = createActivityAction(); return new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY) .addRow(new ListBuilder.RowBuilder() .setTitle("Perform action in app.") .setPrimaryAction(activityAction) ).build(); } public SliceAction createActivityAction() { if (getContext() == null) { return null; } return SliceAction.create( PendingIntent.getActivity( getContext(), 0, new Intent(getContext(), MainActivity.class), 0 ), IconCompat.createWithResource(getContext(), R.drawable.ic_home), ListBuilder.ICON_IMAGE, "Enter app" ); }

Фрагменты также поддерживают другие типы ввода, например переключатели, которые включают состояние в намерение, отправляемое в приложение.
Kotlin
fun createBrightnessSlice(sliceUri: Uri): Slice { val toggleAction = SliceAction.createToggle( createToggleIntent(), "Toggle adaptive brightness", true ) return list(context, sliceUri, ListBuilder.INFINITY) { row { title = "Adaptive brightness" subtitle = "Optimizes brightness for available light" primaryAction = toggleAction } inputRange { inputAction = (brightnessPendingIntent) max = 100 value = 45 } } } fun createToggleIntent(): PendingIntent { val intent = Intent(context, MyBroadcastReceiver::class.java) return PendingIntent.getBroadcast(context, 0, intent, 0) }
Java
public Slice createBrightnessSlice(Uri sliceUri) { if (getContext() == null) { return null; } SliceAction toggleAction = SliceAction.createToggle( createToggleIntent(), "Toggle adaptive brightness", true ); ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY) .addRow(new ListBuilder.RowBuilder() .setTitle("Adaptive brightness") .setSubtitle("Optimizes brightness for available light.") .setPrimaryAction(toggleAction) ).addInputRange(new ListBuilder.InputRangeBuilder() .setInputAction(brightnessPendingIntent) .setMax(100) .setValue(45) ); return listBuilder.build(); } public PendingIntent createToggleIntent() { Intent intent = new Intent(getContext(), MyBroadcastReceiver.class); return PendingIntent.getBroadcast(getContext(), 0, intent, 0); }
Получатель может проверить полученное состояние:
Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.hasExtra(Slice.EXTRA_TOGGLE_STATE)) { Toast.makeText(context, "Toggled: " + intent.getBooleanExtra( Slice.EXTRA_TOGGLE_STATE, false), Toast.LENGTH_LONG).show() } } companion object { const val EXTRA_MESSAGE = "message" } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { public static String EXTRA_MESSAGE = "message"; @Override public void onReceive(Context context, Intent intent) { if (intent.hasExtra(EXTRA_TOGGLE_STATE)) { Toast.makeText(context, "Toggled: " + intent.getBooleanExtra( EXTRA_TOGGLE_STATE, false), Toast.LENGTH_LONG).show(); } } }

Динамические фрагменты
Фрагменты также могут содержать динамический контент. В следующем примере фрагмент теперь включает в себя количество широковещательных сообщений, полученных в его контенте:
Kotlin
fun createDynamicSlice(sliceUri: Uri): Slice { return when (sliceUri.path) { "/count" -> { val toastAndIncrementAction = SliceAction.create( createToastAndIncrementIntent("Item clicked."), actionIcon, ListBuilder.ICON_IMAGE, "Increment." ) list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = toastAndIncrementAction title = "Count: ${MyBroadcastReceiver.receivedCount}" subtitle = "Click me" } } } else -> { list(context, sliceUri, ListBuilder.INFINITY) { row { primaryAction = createActivityAction() title = "URI not found." } } } } }
Java
public Slice createDynamicSlice(Uri sliceUri) { if (getContext() == null || sliceUri.getPath() == null) { return null; } ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY); switch (sliceUri.getPath()) { case "/count": SliceAction toastAndIncrementAction = SliceAction.create( createToastAndIncrementIntent("Item clicked."), actionIcon, ListBuilder.ICON_IMAGE, "Increment." ); listBuilder.addRow( new ListBuilder.RowBuilder() .setPrimaryAction(toastAndIncrementAction) .setTitle("Count: " + MyBroadcastReceiver.sReceivedCount) .setSubtitle("Click me") ); break; default: listBuilder.addRow( new ListBuilder.RowBuilder() .setPrimaryAction(createActivityAction()) .setTitle("URI not found.") ); break; } return listBuilder.build(); } public PendingIntent createToastAndIncrementIntent(String s) { Intent intent = new Intent(getContext(), MyBroadcastReceiver.class) .putExtra(MyBroadcastReceiver.EXTRA_MESSAGE, s); return PendingIntent.getBroadcast(getContext(), 0, intent, 0); }
В этом примере количество показано, но не обновляется автоматически. Вы можете изменить широковещательный приемник, чтобы он уведомлял систему о произошедшем изменении, используя ContentResolver#notifyChange.
Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.hasExtra(Slice.EXTRA_TOGGLE_STATE)) { Toast.makeText( context, "Toggled: " + intent.getBooleanExtra( Slice.EXTRA_TOGGLE_STATE, false ), Toast.LENGTH_LONG ).show() receivedCount++; context.contentResolver.notifyChange(sliceUri, null) } } companion object { var receivedCount = 0 val sliceUri = Uri.parse("content://com.android.example.slicesample/count") const val EXTRA_MESSAGE = "message" } }
Java
public class MyBroadcastReceiver extends BroadcastReceiver { public static int sReceivedCount = 0; public static String EXTRA_MESSAGE = "message"; private static Uri sliceUri = Uri.parse("content://com.android.example.slicesample/count"); @Override public void onReceive(Context context, Intent intent) { if (intent.hasExtra(EXTRA_TOGGLE_STATE)) { Toast.makeText(context, "Toggled: " + intent.getBooleanExtra( EXTRA_TOGGLE_STATE, false), Toast.LENGTH_LONG).show(); sReceivedCount++; context.getContentResolver().notifyChange(sliceUri, null); } } }

Шаблоны
Фрагменты поддерживают различные шаблоны. Подробную информацию о настройках и работе шаблонов можно найти в статье Шаблоны.