Per iniziare

Questa pagina mostra come configurare l'ambiente e creare Sezioni nella tua app.

Nota: Android Studio 3.2 o versioni successive contiene funzionalità e strumenti aggiuntivi che possono aiutarti con lo sviluppo di Slice:

  • Strumento di refactoring AndroidX: richiesto se stai lavorando in un progetto che utilizza le librerie AndroidX.
  • Controlli lint per le sezioni: rileva le anti-pratiche comuni durante la creazione delle sezioni
  • Modello SliceProvider: gestisce il boilerplate durante la creazione di un SliceProvider

Scarica e installa il visualizzatore Slice

Scarica l'ultima versione di esempio dell'APK di Slice Viewer per testare le tue sezioni senza implementare l'API SliceView.

Se ADB non è configurato correttamente nel tuo ambiente, consulta la guida di ADB per ulteriori informazioni.

Installa il visualizzatore Slice sul tuo dispositivo eseguendo il comando seguente nella stessa directory del file slice-viewer.apk scaricato:

adb install -r -t slice-viewer.apk

Esegui il visualizzatore sezioni

Puoi avviare il visualizzatore sezioni dal progetto Android Studio o dalla riga di comando:

Avvia il visualizzatore sezioni dal progetto Android Studio

  1. Nel progetto, seleziona Esegui > Modifica configurazioni...
  2. Nell'angolo in alto a sinistra, fai clic sul segno più verde
  3. Seleziona App Android

  4. Inserisci sezione nel campo del nome.

  5. Seleziona il modulo dell'app nel menu a discesa Modulo.

  6. In Opzioni di avvio, seleziona URL dal menu a discesa Avvia.

  7. Inserisci slice-<your slice URI> nel campo dell'URL.

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

  8. Fai clic su OK.

Avvia lo strumento Visualizzatore sezione tramite ADB (riga di comando)

Esegui l'app da Android Studio:

adb install -t -r <yourapp>.apk

Visualizza la sezione eseguendo questo comando:

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

Visualizzatore sezione che mostra una singola sezione Wi-Fi

Visualizza tutte le sezioni in un unico posto

Oltre ad avviare una singola sezione, puoi visualizzare un elenco permanente delle sezioni.

  • Utilizza la barra di ricerca per cercare manualmente le sezioni tramite URI (ad esempio content://com.example.android.app/hello). Ogni volta che esegui una ricerca, la Sezione viene aggiunta all'elenco.
  • Ogni volta che avvii lo strumento Visualizzatore Slice con un URI Slice, questa viene aggiunta all'elenco.
  • Puoi far scorrere una sezione per rimuoverla dall'elenco.
  • Tocca l'URI della sezione per visualizzare una pagina contenente solo quella sezione. Questo ha lo stesso effetto dell'avvio del visualizzatore Slice con un URI Slice.

Visualizzatore sezione che mostra un elenco di sezioni

Visualizza la sezione in diverse modalità

Un'app che presenta una sezione può modificare la sezione SliceView#mode in fase di runtime, quindi assicurati che la sezione abbia l'aspetto previsto in ogni modalità. Seleziona l'icona del menu nell'area in alto a destra della pagina per cambiare la modalità.

Visualizzatore singola sezione con modalità impostata su "small"

Crea la tua prima sezione

Per creare una sezione, apri il progetto Android Studio, fai clic con il tasto destro del mouse sul pacchetto src e seleziona Nuovo... > Altro > Provider sezione. Questa operazione crea una classe che estende SliceProvider, aggiunge la voce del provider richiesta a AndroidManifest.xml e modifica il tuo build.gradle per aggiungere le dipendenze Slice necessarie.

Di seguito è mostrata la modifica a 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>

Le seguenti dipendenze vengono aggiunte a build.gradle:

Kotlin

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

Java

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

A ogni sezione è associato un URI. Quando una piattaforma vuole visualizzare una sezione, invia una richiesta di associazione alla tua app con questo URI. L'app gestisce quindi questa richiesta e crea dinamicamente la sezione tramite il metodo onBindSlice. La superficie può quindi visualizzare la Sezione quando opportuno.

Di seguito è riportato un esempio di metodo onBindSlice che controlla il percorso dell'URI /hello e restituisce una sezione 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();
}

Utilizza la configurazione di esecuzione per sezione creata nella sezione Visualizzatore sezione in alto, passando l'URI della sezione (ad esempio slice-content://com.android.example.slicesample/hello) della sezione Hello World per visualizzarla nel visualizzatore sezione.

Sezioni interattive

Come per le notifiche, puoi gestire i clic all'interno della sezione collegando gli oggetti PendingIntent che vengono attivati all'interazione dell'utente. L'esempio seguente inizia con una Activity che può ricevere e gestire questi intent:

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

Le sezioni supportano anche altri tipi di input, ad esempio i pulsanti di attivazione/disattivazione, che includono lo stato nell'intent inviato all'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);
}

Il destinatario può quindi verificare lo stato che riceve:

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

Sezioni dinamiche

Le sezioni possono anche includere contenuti dinamici. Nell'esempio seguente, la sezione ora include il numero di trasmissioni ricevute nei suoi contenuti:

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 questo esempio, il conteggio non viene aggiornato automaticamente, anche se viene mostrato. Puoi modificare il ricevitore della trasmissione utilizzando ContentResolver#notifyChange per notificare al sistema che si è verificata una modifica.

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

Modelli

Le sezioni supportano una varietà di modelli. Per ulteriori dettagli sulle opzioni e i comportamenti dei modelli, consulta la sezione Modelli.