Gestire gli eventi del livello dati su Wear

Quando effettui una chiamata all'API del livello dati, puoi ricevere stato della chiamata al termine dell'operazione. Puoi anche ascoltare eventi di dati derivanti da modifiche ai dati che l'app apporta in qualsiasi punto Rete Wear OS by Google.

Per un esempio di come lavorare in modo efficace con l'API del livello dati, consulta le App di esempio Android Datalayer.

Attendi lo stato delle chiamate al livello dati

Chiamate all'API del livello dati, ad esempio una chiamata che utilizza putDataItem del metodo DataClient corso: a volte restituisce un Task<ResultType> oggetto. Non appena l'oggetto Task viene creata l'operazione in coda in background. Se successivamente non intraprendi alcuna azione, l'operazione alla fine completa in silenzio.

Tuttavia, in genere vuoi fare qualcosa con il risultato dopo il completamento dell'operazione, quindi l'oggetto Task consente devi attendere lo stato dei risultati, in modo asincrono o sincrono.

Chiamate asincrone

Se il codice è in esecuzione sul thread principale dell'interfaccia utente, non effettuare chiamate di blocco al API Livello dati. Esegui le chiamate in modo asincrono aggiungendo un metodo di callback all'oggetto Task, che si attiva al completamento dell'operazione:

Kotlin

// Using Kotlin function references
task.addOnSuccessListener(::handleDataItem)
task.addOnFailureListener(::handleDataItemError)
task.addOnCompleteListener(::handleTaskComplete)
...
fun handleDataItem(dataItem: DataItem) { ... }
fun handleDataItemError(exception: Exception) { ... }
fun handleTaskComplete(task: Task<DataItem>) { ... }

Java

// Using Java 8 Lambdas.
task.addOnSuccessListener(dataItem -> handleDataItem(dataItem));
task.addOnFailureListener(exception -> handleDataItemError(exception));
task.addOnCompleteListener(task -> handleTaskComplete(task));

Consulta dell'API Tasks per altre possibilità, inclusa la concatenazione dell'esecuzione di diverse attività.

Chiamate sincrone

Se il tuo codice è in esecuzione su un thread del gestore separato in un servizio in background, come in un WearableListenerService, se le chiamate vengono bloccate. In questo caso, puoi chiamare Tasks.await() sul Task che viene bloccato finché la richiesta non viene completata e restituisce un Result oggetto. Ciò è mostrato nell'esempio seguente.

Nota:assicurati di non chiamare questa funzione durante il thread principale.

Kotlin

try {
    Tasks.await(dataItemTask).apply {
        Log.d(TAG, "Data item set: $uri")
    }
}
catch (e: ExecutionException) { ... }
catch (e: InterruptedException) { ... }

Java

try {
    DataItem item = Tasks.await(dataItemTask);
    Log.d(TAG, "Data item set: " + item.getUri());
} catch (ExecutionException | InterruptedException e) {
  ...
}

Ascolta gli eventi del livello dati

Poiché il livello dati sincronizza e invia i dati tra il dispositivo dispositivi indossabili, solitamente è necessario ascoltare eventi importanti come gli elementi dati creati e i messaggi ricevuti.

Per ascoltare gli eventi del livello dati, hai due opzioni:

Con entrambe le opzioni, sostituisci i metodi di callback degli eventi dati per gli eventi che ti interessa gestire.

Nota: quando scegli, considera l'utilizzo della batteria da parte dell'app un'implementazione listener. WearableListenerService è registrato nel file manifest dell'app e può avviarla, se non è già registrato in esecuzione. Se devi ascoltare gli eventi solo quando l'app è già in esecuzione, come accade spesso con le applicazioni interattive, quindi è consigliabile non utilizzare WearableListenerService. Registra invece un ascoltatore. Ad esempio, utilizza il metodo addListener di DataClient . In questo modo è possibile ridurre il carico sul sistema e l'utilizzo della batteria.

Usa un servizio WearableListener

In genere, crei istanze di WearableListenerService sia su indossabile che su app per dispositivi portatili. Tuttavia, se non ti interessano gli eventi di dati in una delle non dovrai implementare il servizio nell'app.

Ad esempio, puoi avere un'app portatile che imposta e ottiene gli oggetti degli elementi dati e un'app indossabile che rimane in ascolto di questi aggiornamenti per aggiornare la propria UI. La l'app indossabile non aggiorna mai nessuno dei dati, pertanto l'app portatile non rimanere in ascolto di tutti gli eventi di dati provenienti dall'app indossabile.

Alcuni degli eventi che puoi ascoltare con WearableListenerService sono i seguenti:

  • onDataChanged(): Ogni volta che un oggetto elemento dati viene creato, eliminato o modificato, il sistema attiva questo callback su tutti i nodi connessi.
  • onMessageReceived(): un messaggio inviato da trigger nodo questo callback sul nodo target.
  • onCapabilityChanged(): Quando diventa disponibile una funzionalità pubblicizzata da un'istanza della tua app. sulla rete, quell'evento attiva il callback. Se stai cercando un puoi eseguire query isNearby() dei nodi forniti nel callback.

Puoi anche ascoltare eventi da ChannelClient.ChannelCallback, ad esempio onChannelOpened().

Tutti gli eventi precedenti vengono eseguiti in un thread in background, non nel thread principale.

Per creare un WearableListenerService, segui questi passaggi:

  1. Crea un corso che estenda WearableListenerService.
  2. Ascolta gli eventi che ti interessano, come onDataChanged().
  3. Dichiara un filtro per intent nel tuo file manifest Android per notificare al sistema le tue WearableListenerService. Questa dichiarazione consente al sistema di vincolare servizio desiderato.

L'esempio seguente mostra come implementare una WearableListenerService semplice:

Kotlin

private const val TAG = "DataLayerSample"
private const val START_ACTIVITY_PATH = "/start-activity"
private const val DATA_ITEM_RECEIVED_PATH = "/data-item-received"

class DataLayerListenerService : WearableListenerService() {

    override fun onDataChanged(dataEvents: DataEventBuffer) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "onDataChanged: $dataEvents")
        }

        // Loop through the events and send a message
        // to the node that created the data item.
        dataEvents.map { it.dataItem.uri }
                .forEach { uri ->
                    // Get the node ID from the host value of the URI.
                    val nodeId: String = uri.host
                    // Set the data of the message to be the bytes of the URI.
                    val payload: ByteArray = uri.toString().toByteArray()

                    // Send the RPC.
                    Wearable.getMessageClient(this)
                            .sendMessage(nodeId, DATA_ITEM_RECEIVED_PATH, payload)
                }
    }
}

Java

public class DataLayerListenerService extends WearableListenerService {
    private static final String TAG = "DataLayerSample";
    private static final String START_ACTIVITY_PATH = "/start-activity";
    private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "onDataChanged: " + dataEvents);
        }

        // Loop through the events and send a message
        // to the node that created the data item.
        for (DataEvent event : dataEvents) {
            Uri uri = event.getDataItem().getUri();

            // Get the node ID from the host value of the URI.
            String nodeId = uri.getHost();
            // Set the data of the message to be the bytes of the URI.
            byte[] payload = uri.toString().getBytes();

            // Send the RPC.
            Wearable.getMessageClient(this).sendMessage(
                  nodeId,  DATA_ITEM_RECEIVED_PATH, payload);
        }
    }
}

La seguente sezione spiega come utilizzare un filtro per intent con questo listener.

Utilizzare i filtri con WearableListenerService

Un filtro per intent per l'esempio WearableListenerService mostrato nella sezione precedente potrebbe avere il seguente aspetto:

<service android:name=".DataLayerListenerService" android:exported="true" tools:ignore="ExportedService" >
  <intent-filter>
      <action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
      <data android:scheme="wear" android:host="*"
               android:path="/start-activity" />
  </intent-filter>
</service>

In questo filtro, l'azione DATA_CHANGED sostituisce in precedenza ha consigliato l'azione BIND_LISTENER in modo che degli eventi riattivano o avviano la tua app. Questa modifica migliora l'efficienza del sistema e riduce il consumo della batteria e altri costi associati dell'app. In questo esempio, l'orologio ascolta l'evento /start-activity e il il telefono rimane in ascolto della risposta al messaggio /data-item-received.

Si applicano le regole di corrispondenza dei filtri Android standard. Puoi specificare più servizi per manifest, più filtri di intent per servizio, più azioni per filtro e più data stanza per filtro. I filtri possono corrispondere a un host con caratteri jolly o a uno specifico. Per trovare una corrispondenza con un host con caratteri jolly, utilizza host="*". Per corrispondere su un host specifico, specifica host=<node_id>.

Puoi anche trovare una corrispondenza con un percorso letterale o un prefisso di percorso. Per farlo, devi specificare un carattere jolly o un host specifico. In caso contrario, il sistema ignora il percorso specificato.

Per ulteriori informazioni sui tipi di filtri supportati da Wear OS, consulta le documentazione di riferimento dell'API per WearableListenerService.

Per saperne di più sui filtri dati e sulle regole di corrispondenza, consulta la documentazione di riferimento dell'API documentazione di <data> .

Quando fai corrispondere i filtri per intent, ricorda due regole importanti:

  • Se non viene specificato nessuno schema per il filtro per intent, il sistema ignora tutti gli altri attributi URI.
  • Se non viene specificato alcun host per il filtro, il sistema ignora tutti gli attributi del percorso.

Usare un listener in tempo reale

Se alla tua app interessano solo gli eventi a livello dati quando l'utente interagisce con l'app, potrebbe non essere necessario un servizio a lunga esecuzione per gestire ogni modifica ai dati. Nella in questo caso, puoi ascoltare gli eventi in un'attività implementando uno o altre interfacce riportate di seguito:

Per creare un'attività che ascolti eventi di dati:

  1. Implementa le interfacce desiderate.
  2. Nel metodo onCreate() o onResume(), richiama Wearable.getDataClient(this).addListener(), MessageClient.addListener(), CapabilityClient.addListener() o ChannelClient.registerChannelCallback() per inviare una notifica a Google Play servizi che la tua attività vuole ascoltare per gli eventi del livello dati.
  3. Tra onStop() o onPause(), annullare la registrazione di eventuali listener con DataClient.removeListener(), MessageClient.removeListener(), CapabilityClient.removeListener() o ChannelClient.unregisterChannelCallback(),
  4. Se un'attività è interessata solo agli eventi con un prefisso di percorso specifico, puoi aggiungere un listener con un filtro per prefisso appropriato per ricevere solo i dati e lo stato attuale dell'applicazione.
  5. Implementa onDataChanged(), onMessageReceived(), onCapabilityChanged() o metodi da ChannelClient.ChannelCallback, a seconda delle interfacce implementate. Questi metodi vengono richiamati il thread principale oppure puoi specificare un valore Looper personalizzato utilizzando WearableOptions.

Ecco un esempio che implementa DataClient.OnDataChangedListener:

Kotlin

class MainActivity : Activity(), DataClient.OnDataChangedListener {

    public override fun onResume() {
        Wearable.getDataClient(this).addListener(this)
    }

    override fun onPause() {
        Wearable.getDataClient(this).removeListener(this)
    }

    override fun onDataChanged(dataEvents: DataEventBuffer) {
        dataEvents.forEach { event ->
            if (event.type == DataEvent.TYPE_DELETED) {
                Log.d(TAG, "DataItem deleted: " + event.dataItem.uri)
            } else if (event.type == DataEvent.TYPE_CHANGED) {
                Log.d(TAG, "DataItem changed: " + event.dataItem.uri)
            }
        }
    }
}

Java

public class MainActivity extends Activity implements DataClient.OnDataChangedListener {

    @Override
    public void onResume() {
        Wearable.getDataClient(this).addListener(this);
    }

    @Override
    protected void onPause() {
        Wearable.getDataClient(this).removeListener(this);
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        for (DataEvent event : dataEvents) {
            if (event.getType() == DataEvent.TYPE_DELETED) {
                Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
            } else if (event.getType() == DataEvent.TYPE_CHANGED) {
                Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri());
            }
        }
    }
}

Utilizzare i filtri con i listener dal vivo

Come accennato in precedenza, così come puoi specificare i filtri per intent WearableListenerService basati su manifest puoi utilizzare i filtri per intent quando registri un listener d'intenti tramite Indossabile API. Le stesse regole valgono sia per i listener in tempo reale basati su API, sia per listener basati su manifest.

Un pattern comune consiste nel registrare un listener con un percorso o un prefisso di percorso specifico nell'elemento onResume() di un'attività e poi rimuovere il listener nel campo Metodo onPause(). L'implementazione degli ascoltatori in questo modo consente alla tua app di essere più selettivamente ricevere eventi, migliorandone la progettazione e l'efficienza.