Grundlegende Informationen

Auf dieser Seite erfahren Sie, wie Sie Ihre Umgebung einrichten und Slices in Ihrer Anwendung erstellen.

Hinweis: Android Studio 3.2 oder höher enthält zusätzliche Tools und Funktionen für die Slice-Entwicklung:

  • AndroidX-Refaktorierungstool: erforderlich, wenn Sie in einem Projekt arbeiten, das AndroidX-Bibliotheken verwendet.
  • Slice-Lint-Prüfungen: Damit werden gängige Anti-Practices beim Erstellen von Slices abgefangen.
  • Vorlage SliceProvider: bearbeitet den Textbaustein beim Erstellen eines SliceProvider-Objekts

Slice Viewer herunterladen und installieren

Laden Sie die neueste exemplarische Slice Viewer-APK-Version herunter, mit der Sie Ihre Slices testen können, ohne die SliceView API zu implementieren.

Wenn ADB in Ihrer Umgebung nicht richtig eingerichtet ist, finden Sie weitere Informationen in der ADB-Anleitung.

Installieren Sie die Slice Viewer auf Ihrem Gerät. Führen Sie dazu den folgenden Befehl im selben Verzeichnis wie das heruntergeladene slice-viewer.apk aus:

adb install -r -t slice-viewer.apk

Slice-Viewer ausführen

Sie können den Slice Viewer entweder über Ihr Android Studio-Projekt oder über die Befehlszeile starten:

Slice Viewer aus Ihrem Android Studio-Projekt starten

  1. Wählen Sie in Ihrem Projekt Run > Edit Configurations... (Ausführen > Konfigurationen bearbeiten...) aus.
  2. Klicken Sie links oben auf das grüne Pluszeichen.
  3. Wählen Sie Android-App aus.

  4. Geben Sie slice in das Namensfeld ein.

  5. Wählen Sie im Drop-down-Menü Module Ihr App-Modul aus.

  6. Wählen Sie unter Launch Options (Startoptionen) im Drop-down-Menü Launch (Starten) die Option URL (URL) aus.

  7. Geben Sie slice-<your slice URI> in das URL-Feld ein.

    Beispiel: slice-content://com.example.your.sliceuri

  8. Klicken Sie auf OK.

Slice Viewer über ADB (Befehlszeile) starten

Führen Sie Ihre App über Android Studio aus:

adb install -t -r <yourapp>.apk

Rufen Sie das Slice auf, indem Sie den folgenden Befehl ausführen:

adb shell am start -a android.intent.action.VIEW -d slice-<your slice URI>

Slice-Anzeige, in der ein einzelnes WLAN-Slice angezeigt wird

Alle deine Slices an einem Ort ansehen

Sie können nicht nur einen einzelnen Slice starten, sondern auch eine persistente Liste Ihrer Slices abrufen.

  • Verwenden Sie die Suchleiste, um manuell über URI nach Ihren Segmenten zu suchen (z. B. content://com.example.android.app/hello). Bei jeder Suche wird das Slice der Liste hinzugefügt.
  • Jedes Mal, wenn Sie das Slice Viewer-Tool mit einem Slice-URI starten, wird das Slice der Liste hinzugefügt.
  • Sie können ein Slice wischen, um es aus der Liste zu entfernen.
  • Tippen Sie auf den URI des Slice, um eine Seite anzuzeigen, die nur diesen Slice enthält. Dies hat denselben Effekt wie das Starten der Slice Viewer mit einem Slice-URI.

Slice-Anzeige mit einer Liste der Slices

Slice in verschiedenen Modi ansehen

Eine Anwendung, in der ein Slice bereitgestellt wird, kann den SliceView#mode zur Laufzeit ändern. Achten Sie deshalb darauf, dass Ihr Slice in jedem Modus wie erwartet aussieht. Wählen Sie das Menüsymbol oben rechts auf der Seite aus, um den Modus zu ändern.

Einzel-Slice-Viewer mit Modus „Klein“

Ihren ersten Slice erstellen

Öffnen Sie zum Erstellen eines Slice Ihr Android Studio-Projekt, klicken Sie mit der rechten Maustaste auf das Paket src und wählen Sie Neu... > Sonstige > Slice-Anbieter. Dadurch wird eine Klasse erstellt, die SliceProvider erweitert, den erforderlichen Anbietereintrag in die Datei AndroidManifest.xml aufgenommen und die build.gradle so ändert, dass die erforderlichen Slice-Abhängigkeiten hinzugefügt werden.

Die Änderung an AndroidManifest.xml sieht so aus:

<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>

Die folgenden Abhängigkeiten werden zu build.gradle hinzugefügt:

Kotlin

dependencies {
// ...
    implementation "androidx.slice:slice-builders-ktx:(latest version)"
// ...
}

Java

dependencies {
// ...
    implementation "androidx.slice:slice-builders:(latest version)"
// ...
}

Jedem Slice ist ein URI zugeordnet. Wenn mit einer Oberfläche ein Slice angezeigt werden soll, wird mit diesem URI eine Bindungsanfrage an Ihre Anwendung gesendet. Die Anwendung verarbeitet diese Anfrage und erstellt das Slice dynamisch über die Methode onBindSlice. Auf der Oberfläche kann dann gegebenenfalls das Slice angezeigt werden.

Im Folgenden finden Sie ein Beispiel für eine onBindSlice-Methode, die den URI-Pfad /hello prüft und einen Hello World-Slice zurückgibt:

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();
}

Verwenden Sie die Slice-Ausführungskonfiguration, die Sie oben im Abschnitt „Slice-Anzeige“ erstellt haben, und übergeben Sie den Slice-URI (z. B. slice-content://com.android.example.slicesample/hello) des Hello World-Slice, um ihn in der Slice-Anzeige anzusehen.

Interaktive Slices

Ähnlich wie bei Benachrichtigungen können Sie Klicks im Slice verarbeiten, indem Sie PendingIntent-Objekte anhängen, die durch eine Nutzerinteraktion ausgelöst werden. Im folgenden Beispiel wird ein Activity gestartet, der diese Intents empfangen und verarbeiten kann:

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"
    );
}

Slices unterstützen auch andere Eingabetypen, z. B. Ein-/Aus-Schaltflächen, bei denen der Status im Intent enthalten ist, der an die Anwendung gesendet wird.

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);
}

Der Empfänger kann dann den empfangenen Status prüfen:

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();
        }
    }
}

Dynamische Slices

Slices können auch dynamische Inhalte enthalten. Im folgenden Beispiel enthält der Slice jetzt die Anzahl der empfangenen Broadcasts im Inhalt:

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);
}

In diesem Beispiel wird zwar die Anzahl angezeigt, sie wird aber nicht automatisch aktualisiert. Sie können den Broadcast-Empfänger so anpassen, dass das System mit ContentResolver#notifyChange über eine Änderung informiert wird.

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);
        }
    }
}

Vorlagen

Slices unterstützen eine Vielzahl von Vorlagen. Weitere Informationen zu Vorlagenoptionen und -verhalten finden Sie unter Vorlagen.