Eseguire la migrazione delle app Wear ad API Google

A partire dalla versione 11.8.0 di Google Play Services, verrà eseguita la migrazione delle app per Wear OS. da GoogleApiClient e utilizzare invece oggetti client basati sulla classe GoogleApi.

L'utilizzo di GoogleApi semplifica la configurazione delle operazioni asincrone. Ad esempio, come descritto nell'introduzione al API Tasks, puoi ottenere un oggetto Task anziché un PendingResult oggetto.

Questa pagina include:

  • Una tabella dei componenti sostitutivi
  • Esempio di aggiornamento di un'app esistente per l'utilizzo dell'API Tasks

Nota: questo aggiornamento non riguarda le app Wear OS per Cina, che in genere utilizzano la versione 10.2.0 di Google Play Services.

Nota: questa API è attualmente disponibile solo su smartphone Android. e orologi Wear OS accoppiati con smartphone Android. Per gli orologi Wear OS accoppiati con iOS smartphone, le app possono interrogare altre API basate su cloud se è disponibile una connessione a Internet.

Sostituzioni di componenti deprecati

Quando utilizzi corsi che estendono la classe GoogleApi, come DataClient e MessageClient, l'SDK Google Play Services gestisce connessioni a Google Play Services per te.

Le app che usano le classi sostitutive riportate di seguito non devono creare e gestisci GoogleApiClient di oggetti strutturati. Consulta anche l'articolo sull'accesso API di Google e pagina di riferimento per la classe Wearable.

La seguente tabella contiene componenti deprecati e i relativi sostituzioni:

Componente obsoleto Componente sostitutivo
CapabilityApi CapabilityClient
Channel ChannelClient.Channel
ChannelApi ChannelClient
DataApi DataClient
MessageApi MessageClient
NodeApi NodeClient

Tieni inoltre presente quanto segue:

Esempio di migrazione per un'app Wear

A titolo di esempio di migrazione, gli snippet di codice riportati di seguito illustrano il modo in cui Dati di Wear L'esempio di livello, che utilizza l'API Data Layer, è aggiornato alla versione 11.8.0 di Google Play Services. Se l'app ha un modulo per smartphone, potrebbero essere simili a quelli del modulo Wear.

Aggiorna la dipendenza su Google Play Services

Poiché la tua app potrebbe dipendere da una versione precedente di Google Play Services, aggiorna la seguente dipendenza nel file build.gradle di il tuo modulo Wear:

dependencies {
...
compile 'com.google.android.gms:play-services-wearable:11.8.0'
}

Aggiorna le istruzioni di importazione dell'app

Importa le classi necessarie, inclusi i corsi nell'API Tasks.

Ad esempio, in precedenza Livello dati Wear sample ha incluso la seguente istruzione di importazione nel MainActivity.java file. Questa istruzione import da rimuovere:

Kotlin

...
import com.google.android.gms.common.api.GoogleApiClient
...

Java

...
import com.google.android.gms.common.api.GoogleApiClient;
...

Nella sezione Wear Esempio di livello dati, istruzioni import come le precedenti sono stati sostituiti, ad esempio, con il seguente (il secondo è per gestire le eccezioni delle attività):

Kotlin

...
import com.google.android.gms.tasks.Tasks
import java.util.concurrent.ExecutionException
...

Java

...
import com.google.android.gms.tasks.Tasks;
import java.util.concurrent.ExecutionException;
...

Implementare le nuove interfacce client

Rimuovi qualsiasi utilizzo di GoogleApiClient e le interfacce associate (ConnectionCallbacks, OnConnectionFailedListener e così via) e sostituisci l'altra Implementazioni dell'ascoltatore con le nuove versioni. I metodi effettivi per di solito hanno gli stessi nomi di prima, quindi la modifica principale simile all'esempio riportato di seguito.

L'attività principale dell'esempio del livello dati Wear (come indicato in un su GitHub) ha implementato, ad esempio, CapabilityApi.CapabilityListener. Ma ora l'attività principale implementa CapabilityClient.OnCapabilityChangedListener.

Di seguito è riportato un confronto delle definizioni delle classi.

Ecco uno snippet prima dell'utilizzo della versione 11.8.0 di Google Play Google Cloud:

Kotlin

class MainActivity :
        Activity(),
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        DataApi.DataListener,
        MessageApi.MessageListener,
        CapabilityApi.CapabilityListener

Java

public class MainActivity extends Activity implements
  ConnectionCallbacks,
  OnConnectionFailedListener,
  DataApi.DataListener,
  MessageApi.MessageListener,
  CapabilityApi.CapabilityListener

Ecco uno snippet dopo l'utilizzo della versione 11.8.0 di Google Play Google Cloud:

Kotlin

class MainActivity :
        Activity(),
        DataClient.OnDataChangedListener,
        MessageClient.OnMessageReceivedListener,
        CapabilityClient.OnCapabilityChangedListener

Java

public class MainActivity extends Activity implements
  DataClient.OnDataChangedListener,
  MessageClient.OnMessageReceivedListener,
  CapabilityClient.OnCapabilityChangedListener

Rimuovi e aggiungi listener

I nuovi oggetti client vengono memorizzati nella cache e condivisi tra GoogleApi istanze, quindi non è necessario tenere il membro variabili; creare clienti è poco costoso e non perderanno e ascoltatori.

Di seguito è riportato uno snippet del livello dati Wear aggiornato esempio:

Kotlin

override fun onResume() {
    super.onResume()
    Wearable.getDataClient(this).addListener(this)
    Wearable.getMessageClient(this).addListener(this)
    Wearable.getCapabilityClient(this)
            .addListener(
                    this,
                    Uri.parse("wear://"),
                    CapabilityClient.FILTER_REACHABLE
            )
}

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

Java

@Override
protected void onResume() {
  super.onResume();
  Wearable.getDataClient(this).addListener(this);
  Wearable.getMessageClient(this).addListener(this);
  Wearable.getCapabilityClient(this)
  .addListener(
    this, Uri.parse("wear://"), CapabilityClient.FILTER_REACHABLE);
}

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

Richiesta di informazioni con l'API Tasks

Ti consigliamo di richiedere informazioni al di fuori degli ascoltatori che aggiornano nell'app in caso di modifica dei dati. In questi casi, invia una richiesta utilizzando un client come DataClient, insieme all'API Tasks e una classe di risultati (ovvero Task<ResultType>).

Ad esempio, come mostrato nel livello dati Wear esempio, puoi utilizzare l'API Tasks per trovare nodi connessi con qualsiasi capacità specifica:

Kotlin

private fun showNodes(vararg capabilityNames: String) {
    Wearable.getCapabilityClient(this)
            .getAllCapabilities(CapabilityClient.FILTER_REACHABLE).apply {
                addOnSuccessListener { capabilityInfoMap ->
                    val nodes: Set<Node> = capabilityInfoMap
                            .filter { capabilityNames.contains(it.key) }
                            .flatMap { it.value.nodes }
                            .toSet()
                    showDiscoveredNodes(nodes)
                }
            }
}

private fun showDiscoveredNodes(nodes: Set<Node>) {
    val nodesList: Set<String> = nodes.map { it.displayName }.toSet()
    val msg: String = if (nodesList.isEmpty()) {
        Log.d(TAG, "Connected Nodes: No connected device was found for the given capabilities")
        getString(R.string.no_device)
    } else {
        Log.d(TAG, "Connected Nodes: ${nodesList.joinToString(separator = ", ")}")
        getString(R.string.connected_nodes, nodesList)
    }
    Toast.makeText(this@MainActivity, msg, Toast.LENGTH_LONG).show()
}

Java

private void showNodes(final String... capabilityNames) {
  Task<Map<String, CapabilityInfo>> capabilitiesTask =
    Wearable.getCapabilityClient(this)
            .getAllCapabilities(CapabilityClient.FILTER_REACHABLE);
  capabilitiesTask.addOnSuccessListener(new
    OnSuccessListener<Map<String, CapabilityInfo>>() {
      @Override
      public void onSuccess(Map<String, CapabilityInfo>
        capabilityInfoMap) {
          Set<Node> nodes = new HashSet<>();
          if (capabilityInfoMap.isEmpty()) {
            showDiscoveredNodes(nodes);
            return;
          }
          for (String capabilityName : capabilityNames) {
            CapabilityInfo capabilityInfo = capabilityInfoMap.get(capabilityName);
            if (capabilityInfo != null) {
              nodes.addAll(capabilityInfo.getNodes());
            }
          }
          showDiscoveredNodes(nodes);
      }
  });
}

private void showDiscoveredNodes(Set<Node> nodes) {
  List<String> nodesList = new ArrayList<>();
  for (Node node : nodes) {
    nodesList.add(node.getDisplayName());
  }
  LOGD(TAG, "Connected Nodes: " + (nodesList.isEmpty()
    ? "No connected device was found for the given capabilities"
    : TextUtils.join(",", nodesList)));
  String msg;
  if (!nodesList.isEmpty()) {
    msg = getString(R.string.connected_nodes, TextUtils.join(", ", nodesList));
  } else {
    msg = getString(R.string.no_device);
  }
  Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
}

Per codice aggiuntivo che utilizza le API Wearable e Tasks, consulta le Livello dati Wear esempio. Come esempio di utilizzo di attività complesse al di fuori del thread dell'interfaccia utente o in un servizio, è disponibile un'altra opzione. Ecco un esempio di come bloccare un'attività e ottenere i risultati in modo sincrono:

Kotlin

override fun doInBackground(vararg params: Asset): Bitmap? {
    if (params.isNotEmpty()) {
        val asset = params[0]
        val getFdForAssetResponseTask: Task<DataClient.GetFdForAssetResponse> =
                Wearable.getDataClient(applicationContext).getFdForAsset(asset)
        return try {
            // Block on a task and get the result synchronously. This is generally done
            // when executing a task inside a separately managed background thread. Doing
            // this on the main (UI) thread can cause your application to become
            // unresponsive.
            val getFdForAssetResponse: DataClient.GetFdForAssetResponse =
                    Tasks.await(getFdForAssetResponseTask)
            getFdForAssetResponse.inputStream?.let { assetInputStream ->
                BitmapFactory.decodeStream(assetInputStream)
            } ?: run {
                Log.w(TAG, "Requested an unknown Asset.")
                null
            }

        } catch (exception: ExecutionException) {
            Log.e(TAG, "Failed retrieving asset, Task failed: $exception")
            return null
        } catch (exception: InterruptedException) {
            Log.e(TAG, "Failed retrieving asset, interrupt occurred: $exception")
            return null
        }

    } else {
        Log.e(TAG, "Asset must be non-null")
        return null
    }
}

override fun onPostExecute(bitmap: Bitmap?) {
    bitmap?.also {
        Log.d(TAG, "Setting background image on second page..")
        moveToPage(1)
        assetFragment.setBackgroundImage(it)
    }
}

Java

@Override
protected Bitmap doInBackground(Asset... params) {
  if (params.length > 0) {
    Asset asset = params[0];
    Task<DataClient.GetFdForAssetResponse> getFdForAssetResponseTask =
      Wearable.getDataClient(getApplicationContext()).getFdForAsset(asset);
    try {
      // Block on a task and get the result synchronously. This is generally done
      // when executing a task inside a separately managed background thread. Doing
      // this on the main (UI) thread can cause your application to become
      // unresponsive.
      DataClient.GetFdForAssetResponse getFdForAssetResponse =
        Tasks.await(getFdForAssetResponseTask);
      InputStream assetInputStream = getFdForAssetResponse.getInputStream();
      if (assetInputStream != null) {
        return BitmapFactory.decodeStream(assetInputStream);
      } else {
        Log.w(TAG, "Requested an unknown Asset.");
        return null;
      }

    } catch (ExecutionException exception) {
      Log.e(TAG, "Failed retrieving asset, Task failed: " + exception);
      return null;
    } catch (InterruptedException exception) {
      Log.e(TAG, "Failed retrieving asset, interrupt occurred: " + exception);
      return null;
    }
  } else {
    Log.e(TAG, "Asset must be non-null");
    return null;
  }
}

@Override
protected void onPostExecute(Bitmap bitmap) {
  if (bitmap != null) {
    LOGD(TAG, "Setting background image on second page..");
    moveToPage(1);
    assetFragment.setBackgroundImage(bitmap);
  }
}