À partir de la version 11.8.0 des services Google Play, les applications Wear OS ne doivent plus utiliser la classe GoogleApiClient
et privilégier les objets client basés sur la classe
GoogleApi
.
L'utilisation de
GoogleApi
facilite la configuration d'opérations asynchrones.
Par exemple, comme décrit dans l'introduction à l'API Tasks, vous pouvez obtenir un objet Task
au lieu d'un objet
PendingResult
.
Cette page comprend les éléments suivants :
- Une table des composants de remplacement
- Un exemple de mise à jour d'une application existante pour utiliser l'API Tasks
Remarque : Cette mise à jour ne s'applique pas aux applications Wear OS pour la Chine, qui utilisent généralement la version 10.2.0 des services Google Play.
Remarque : Cette API n'est actuellement disponible que sur les téléphones Android et les montres Wear OS associées à des téléphones Android. Pour les montres Wear OS associées à des téléphones iOS, les applications peuvent interroger d'autres API basées sur le cloud si la connexion Internet est disponible.
Remplacement de composants obsolètes
Lorsque vous utilisez des classes qui étendent la classe
GoogleApi
, telles que
DataClient
et
MessageClient
, le SDK des services Google Play gère automatiquement les connexions aux services Google Play.
Les applications qui utilisent les classes de remplacement ci-dessous n'ont pas besoin de créer ni de gérer d'objets GoogleApiClient
. Consultez également Accéder aux API Google et la page de référence de la classe Wearable.
Le tableau suivant contient les composants obsolètes et leurs remplacements :
Composant obsolète | Composant de remplacement |
CapabilityApi
|
CapabilityClient
|
Channel
|
ChannelClient.Channel
|
ChannelApi
|
ChannelClient
|
DataApi
|
DataClient
|
MessageApi
|
MessageClient
|
NodeApi
|
NodeClient
|
Notez également ce qui suit :
- Pour les notifications de modifications de chaînes,
Channel.ChannelListener
est remplacé parChannelClient.ChannelCallback
- Afin de définir le thread pour les rappels d'écouteur,
GoogleApiClient.Builder.setHandler
est remplacé par la méthodesetLooper
deWearableOptions.Builder
.
Exemple de migration d'une application Wear
À titre d'exemple de migration, les extraits de code ci-dessous montrent comment l'exemple de couche de données Wear, qui utilise l'API Data Layer, a été mis à jour pour la version 11.8.0 des services Google Play. Si votre application comporte un module de téléphone, ses mises à jour peuvent être semblables à celles du module Wear.
Mettre à jour la dépendance aux services Google Play
Étant donné que votre application peut dépendre d'une version antérieure des services Google Play, mettez à jour la dépendance suivante dans le fichier build.gradle
de votre module Wear :
dependencies { ... compile 'com.google.android.gms:play-services-wearable:11.8.0' }
Mettre à jour les instructions d'importation de votre application
Importez les classes nécessaires, y compris dans l'API Tasks.
Par exemple, l'exemple de couche de données Wear contenait l'instruction d'importation suivante dans le fichier MainActivity.java
. Cette instruction import
doit être supprimée :
Kotlin
... import com.google.android.gms.common.api.GoogleApiClient ...
Java
... import com.google.android.gms.common.api.GoogleApiClient; ...
Dans l'exemple de couche de données Wear, les instructions import
telles que celles indiquées ci-dessus ont été remplacées, par exemple, par les suivantes (la seconde sert à gérer les exceptions de tâche) :
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; ...
Implémenter les nouvelles interfaces client
Supprimez toute utilisation de la classe GoogleApiClient
et des interfaces associées (ConnectionCallbacks
, OnConnectionFailedListener
, etc.) et remplacez les autres implémentations d'écouteur par leurs nouvelles versions. Les méthodes de remplacement utilisées portent généralement les mêmes noms qu'avant. La modification principale est donc semblable à l'exemple ci-dessous.
L'activité principale de l'exemple de couche de données Wear (comme indiqué dans une différence sur GitHub) avait, par exemple, implémenté l'interface CapabilityApi.CapabilityListener
. Mais désormais, l'activité principale implémente CapabilityClient.OnCapabilityChangedListener
.
Vous trouverez ci-dessous un comparatif des définitions de classes.
Voici un extrait de code avant l'utilisation de la version 11.8.0 des services Google Play :
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
Voici un extrait de code après l'utilisation de la version 11.8.0 des services Google Play :
Kotlin
class MainActivity : Activity(), DataClient.OnDataChangedListener, MessageClient.OnMessageReceivedListener, CapabilityClient.OnCapabilityChangedListener
Java
public class MainActivity extends Activity implements DataClient.OnDataChangedListener, MessageClient.OnMessageReceivedListener, CapabilityClient.OnCapabilityChangedListener
Supprimer et ajouter des écouteurs
Les nouveaux objets client sont mis en cache et partagés entre les instances
GoogleApi
. Il n'est donc pas nécessaire de conserver les variables membres. Les clients sont peu coûteux à créer et ne perdent pas leurs écouteurs.
Vous trouverez ci-dessous un extrait de l'exemple de couche de données Wear révisé :
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); }
Demander des informations avec l'API Tasks
Vous pouvez demander des informations en dehors des écouteurs qui mettent à jour votre application en cas de modification des données. Dans ce cas, exécutez une requête à l'aide d'un client tel que
DataClient
, conjointement avec l'API Tasks et une classe de résultat (telle que Task<ResultType>
).
Par exemple, comme illustré dans l'exemple de couche de données Wear, vous pouvez utiliser l'API Tasks pour rechercher des nœuds connectés présentant les fonctionnalités suivantes :
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(); }
Pour obtenir du code supplémentaire utilisant les API Wearable et Tasks, consultez l'exemple de couche de données Wear. Il existe une autre option qui permet d'utiliser des tâches lourdes en dehors du thread UI ou dans un service. Voici un exemple de blocage d'une tâche et d'obtention des résultats de manière synchrone :
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); } }