На этой странице показано, как настроить среду и создать фрагменты в своем приложении.
Примечание . Android Studio 3.2 или более поздней версии содержит дополнительные инструменты и функции, которые могут помочь вам в разработке Slice:
- Инструмент рефакторинга AndroidX: необходим, если вы работаете над проектом, в котором используются библиотеки AndroidX.
- Проверка срезов: выявляет распространенные антипрактики при создании срезов.
- Шаблон
SliceProvider
: обрабатывает шаблон при созданииSliceProvider
Загрузите и установите программу просмотра фрагментов
Загрузите последний образец APK-версии Slice Viewer , который вы можете использовать для тестирования своих срезов без реализации API SliceView
.
Если ADB не настроен должным образом в вашей среде, дополнительную информацию см. в руководстве по ADB .
Установите Slice Viewer на свое устройство, выполнив следующую команду в том же каталоге, где находится загруженный slice-viewer.apk
:
adb install -r -t slice-viewer.apk
Запустите программу просмотра фрагментов
Вы можете запустить Slice Viewer либо из проекта Android Studio, либо из командной строки:
Запустите Slice Viewer из проекта Android Studio.
- В своем проекте выберите «Выполнить» > «Редактировать конфигурации...».
- В левом верхнем углу нажмите зеленый плюсик
Выберите приложение для Android
Введите фрагмент в поле имени
Выберите модуль приложения в раскрывающемся списке «Модуль».
В разделе «Параметры запуска» выберите URL-адрес из раскрывающегося списка «Запуск» .
Введите
slice-<your slice URI>
в поле URL.Пример:
slice-content://com.example.your.sliceuri
Нажмите ОК
Запустите инструмент просмотра фрагментов через ADB (командная строка)
Запустите приложение из Android Studio:
adb install -t -r <yourapp>.apk
Просмотрите свой срез, выполнив следующую команду:
adb shell am start -a android.intent.action.VIEW -d slice-<your slice URI>
Средство просмотра фрагментов, показывающее один фрагмент Wi-Fi
Просматривайте все свои фрагменты в одном месте
Помимо запуска одного слайса, вы можете просмотреть постоянный список ваших слайсов.
- Используйте панель поиска для поиска фрагментов вручную через URI (например,
content://com.example.android.app/hello
). Каждый раз при поиске фрагмент добавляется в список. - Каждый раз, когда вы запускаете инструмент просмотра фрагментов с URI фрагмента, фрагмент добавляется в список.
- Вы можете провести по фрагменту, чтобы удалить его из списка.
- Коснитесь URI фрагмента, чтобы увидеть страницу, содержащую только этот фрагмент. Это имеет тот же эффект, что и запуск средства просмотра фрагментов с URI фрагмента.
Средство просмотра фрагментов, показывающее список фрагментов
Просмотр фрагмента в разных режимах
Приложение, представляющее срез, может изменять SliceView#mode
во время выполнения, поэтому вам следует убедиться, что ваш срез выглядит так, как ожидалось, в каждом режиме. Выберите значок меню в правом верхнем углу страницы, чтобы изменить режим.
Средство просмотра одного фрагмента с режимом «маленький»
Создайте свой первый кусочек
Чтобы создать срез, откройте проект Android Studio, щелкните правой кнопкой мыши пакет src
и выберите «Создать...» > «Другое» > «Поставщик срезов» . При этом создается класс, который расширяет 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
добавляются следующие зависимости:
Котлин
dependencies { // ... implementation "androidx.slice:slice-builders-ktx:(latest version)" // ... }
Ява
dependencies { // ... implementation "androidx.slice:slice-builders:(latest version)" // ... }
Каждый срез имеет связанный URI. Когда поверхность хочет отобразить фрагмент, она отправляет запрос привязки в ваше приложение с этим URI. Затем ваше приложение обрабатывает этот запрос и динамически создает фрагмент с помощью метода onBindSlice
. Затем поверхность может отображать срез, когда это необходимо.
Ниже приведен пример метода onBindSlice
, который проверяет путь URI /hello
и возвращает фрагмент Hello World :
Котлин
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." } } } }
Ява
@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(); }
Используйте конфигурацию запуска среза , которую вы создали в разделе «Просмотр срезов» выше, передав свой URI среза (например, slice-content://com.android.example.slicesample/hello
) среза Hello World , чтобы просмотреть его в Просмотрщик срезов.
Интерактивные фрагменты
Подобно уведомлениям, вы можете обрабатывать клики внутри вашего Slice, присоединяя объекты PendingIntent
, которые активируются при взаимодействии с пользователем. В приведенном ниже примере запускается Activity
, которое может получать и обрабатывать эти намерения:
Котлин
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" ) }
Ява
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" ); }
Срезы также поддерживают другие типы входных данных, например переключатели, которые включают состояние в намерении, отправляемом в приложение.
Котлин
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) }
Ява
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); }
Затем получатель может проверить полученное состояние:
Котлин
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" } }
Ява
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(); } } }
Динамические срезы
Срезы также могут содержать динамический контент. В следующем примере фрагмент теперь включает в себя количество полученных трансляций:
Котлин
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." } } } } }
Ява
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
.
Котлин
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" } }
Ява
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); } } }
Шаблоны
Срезы поддерживают множество шаблонов. Дополнительные сведения о параметрах и поведении шаблонов см. в разделе Шаблоны .