Na tej stronie dowiesz się, jak skonfigurować środowisko i utworzyć wycinki w aplikacji.
Uwaga: Android Studio w wersji 3.2 lub nowszej zawiera dodatkowe narzędzia i funkcje, które mogą pomóc w tworzeniu wycinków:
- Narzędzie do refaktoryzacji AndroidX: wymagane, jeśli pracujesz w projekcie, który korzysta z bibliotek AndroidX.
- Sprawdzanie lintowania wycinków: wychwytywanie typowych elementów antypraktycznych podczas tworzenia wycinków
- Szablon
SliceProvider
: obsługuje schematy podczas tworzenia obiektuSliceProvider
Pobieranie i instalowanie przeglądarki wycinków
Pobierz najnowszą przykładową wersję pliku APK z podglądem wycinków, której możesz używać do testowania wycinków bez implementowania interfejsu SliceView
API.
Jeśli narzędzie ADB nie jest prawidłowo skonfigurowane w Twoim środowisku, zapoznaj się z przewodnikiem ADB, by dowiedzieć się więcej.
Zainstaluj na urządzeniu przeglądarkę wycinków, uruchamiając to polecenie w tym samym katalogu, w którym znajduje się pobrany plik slice-viewer.apk
:
adb install -r -t slice-viewer.apk
Uruchamianie przeglądarki wycinków
Wyświetlający wycinki możesz uruchomić z poziomu projektu Android Studio lub z wiersza poleceń:
Uruchamianie przeglądarki wycinków z projektu Android Studio
- W projekcie wybierz Uruchom > Edytuj konfiguracje...
- W lewym górnym rogu kliknij zielony znak plus.
Wybierz Aplikacja na Androida
W polu nazwy wpisz slice
Wybierz moduł aplikacji w menu Moduł.
W sekcji Launch Options (Opcje uruchamiania) wybierz URL z menu Uruchom.
Wpisz
slice-<your slice URI>
w polu adresu URLPrzykład:
slice-content://com.example.your.sliceuri
Kliknij OK.
Uruchamianie narzędzia Wyświetlający wycinki za pomocą ADB (wiersz poleceń)
Uruchom aplikację z Android Studio:
adb install -t -r <yourapp>.apk
Wyświetl wycinek, uruchamiając to polecenie:
adb shell am start -a android.intent.action.VIEW -d slice-<your slice URI>
Podgląd wycinków przedstawiający pojedynczy wycinek sieci Wi-Fi
Wyświetlanie wszystkich wycinków w jednym miejscu
Oprócz uruchomienia pojedynczego wycinka możesz wyświetlić stałą listę wycinków.
- Użyj paska wyszukiwania, aby ręcznie wyszukać wycinki za pomocą identyfikatora URI (na przykład
content://com.example.android.app/hello
). Za każdym razem, gdy przeprowadzasz wyszukiwanie, wycinek jest dodawany do listy. - Za każdym razem, gdy uruchamiasz narzędzie Wyświetlający wycinek z identyfikatorem URI wycinka, wycinek jest dodawany do listy.
- Możesz przesunąć wycinek, aby usunąć go z listy.
- Kliknij identyfikator URI wycinka, aby wyświetlić stronę zawierającą tylko ten wycinek. Działa to tak samo jak uruchomienie przeglądarki wycinków za pomocą identyfikatora URI wycinka.
Przeglądarka wycinków wyświetlająca listę wycinków
Wyświetlanie wycinka w różnych trybach
Aplikacja wyświetlająca wycinek może modyfikować SliceView#mode
w czasie działania, dlatego upewnij się, że wygląda on zgodnie z oczekiwaniami w każdym trybie.
Aby zmienić tryb, wybierz ikonę menu w prawym górnym rogu strony.
Przeglądarka pojedynczego wycinka z trybem „małym”
Tworzenie pierwszego wycinka
Aby utworzyć wycinek, otwórz projekt Android Studio, kliknij prawym przyciskiem myszy pakiet src
i wybierz Nowy... > Inne > Dostawca wycinka. Spowoduje to utworzenie klasy, która rozszerza zakres SliceProvider
, doda wymagany wpis dostawcy do AndroidManifest.xml
i modyfikuje build.gradle
, aby dodać wymagane zależności wycinka.
Poniżej przedstawiono modyfikację elementu 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
dodaje te zależności:
Kotlin
dependencies { // ... implementation "androidx.slice:slice-builders-ktx:(latest version)" // ... }
Java
dependencies { // ... implementation "androidx.slice:slice-builders:(latest version)" // ... }
Z każdym wycinkiem jest powiązany powiązany identyfikator URI. Gdy platforma chce wyświetlić wycinek, wysyła do aplikacji żądanie powiązania z tym identyfikatorem URI. Aplikacja obsługuje to żądanie i dynamicznie kompiluje wycinek za pomocą metody onBindSlice
. Powierzchnia może następnie wyświetlić Wycinek w odpowiednich przypadkach.
Poniżej znajdziesz przykład metody onBindSlice
, która sprawdza ścieżkę identyfikatora URI /hello
i zwraca wycinek 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(); }
Użyj konfiguracji uruchamiania wycinka utworzonej w sekcji Wyświetlający wycinek powyżej, aby przekazać identyfikator URI wycinka (na przykład slice-content://com.android.example.slicesample/hello
) wycinka Hello World, aby wyświetlić go w podglądzie wycinka.
Interaktywne wycinki
Podobnie jak w przypadku powiadomień, możesz obsługiwać kliknięcia w wycinku, dołączając obiekty PendingIntent
wywoływane podczas interakcji użytkownika. Przykład poniżej rozpoczyna się Activity
, który może odbierać i obsługiwać te intencje:
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" ); }
Wycinki obsługują też inne typy danych wejściowych, np. przełączniki, które uwzględniają stan w intencji wysyłanej do aplikacji.
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); }
Odbiorca może wówczas sprawdzić stan otrzymanych danych:
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(); } } }
Wycinki dynamiczne
Wycinki mogą też zawierać zawartość dynamiczną. W poniższym przykładzie wycinek zawiera teraz liczbę transmisji odebranych w treści:
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); }
W tym przykładzie liczba jest wyświetlana, ale nie aktualizuje się sama. Za pomocą ContentResolver#notifyChange
możesz zmodyfikować odbiornik, aby powiadamiać system o zmianie.
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); } } }
Szablony
Wycinki obsługują różne szablony. Więcej informacji o opcjach i działaniach szablonów znajdziesz w sekcji Szablony.