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:
- Per le notifiche relative alle modifiche ai canali, il valore
Channel.ChannelListener
viene sostituito daChannelClient.ChannelCallback
- Per impostare il thread per i callback del listener,
GoogleApiClient.Builder.setHandler
viene sostituito dal MetodosetLooper
diWearableOptions.Builder
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); } }