Migracja aplikacji na Wear do Google API

Od wersji 11.8.0 usług Google Play, aplikacje na Wear OS powinny zostać przeniesione od GoogleApiClient i używaj obiektów klienta opartych na klasie GoogleApi.

Użycie usługi GoogleApi ułatwia konfigurowanie operacji asynchronicznych. Na przykład jak opisano we wprowadzeniu do Tasks API możesz uzyskać obiekt Task zamiast PendingResult obiekt.

Na tej stronie znajdują się:

  • Tabela komponentów zamiennych
  • Przykład aktualizowania istniejącej aplikacji w celu użycia interfejsu Tasks API

Uwaga: ta aktualizacja nie dotyczy aplikacji na Wear OS na Chiny, które zwykle korzystają z Usług Google Play w wersji 10.2.0.

Uwaga: ten interfejs API jest obecnie dostępny tylko na telefonach z Androidem. i zegarki z Wear OS sparowane z telefonami z Androidem. Zegarki z Wear OS sparowane z iOS aplikacje mogą wysyłać zapytania do innych interfejsów API działających w chmurze, jeśli dostępne jest połączenie z internetem.

Zastępowanie wycofanych komponentów

Gdy używasz klas, które rozszerzają klasę GoogleApi, np. DataClient i MessageClient, zarządza pakiet SDK Usług Google Play połączeń z Usługami Google Play.

W aplikacjach korzystających z klas zastępczych nie trzeba tworzyć zarządzaj: GoogleApiClient obiektów. Patrz też Uzyskiwanie dostępu interfejsów API Google oraz stronie referencyjnej klasy urządzenia do noszenia.

Poniższa tabela zawiera wycofane komponenty i ich zamienniki:

Wycofany komponent Komponent zastępczy
CapabilityApi CapabilityClient
Channel ChannelClient.Channel
ChannelApi ChannelClient
DataApi DataClient
MessageApi MessageClient
NodeApi NodeClient

Pamiętaj też o tych kwestiach:

Przykład migracji aplikacji na Wear

Fragmenty kodu poniżej pokazują przykład migracji Dane dotyczące Wear Próbka warstwy, która korzysta z interfejsu API warstwy danych, została zaktualizowana dla wersji 11.8.0 Usług Google Play. Jeśli aplikacja ma moduł telefonu, mogą być podobne do aktualizacji modułu Wear.

Zaktualizuj zależność w Usługach Google Play

Twoja aplikacja może zależeć od wcześniejszej wersji Usług Google Play, zaktualizuj tę zależność w pliku build.gradle modułowi Wear:

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

Zaktualizuj instrukcje importowania aplikacji

Zaimportuj niezbędne zajęcia, w tym je w interfejsie Tasks API.

Na przykład: dawniej Wear Data Wear przykład umieścił tę deklarację na temat importu w MainActivity.java. Ta instrukcja import należy usunąć:

Kotlin

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

Java

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

W kategorii Wear Przykład warstwy danych, instrukcje import takie jak powyżej zostały zastąpione na przykład następującym (drugi dotyczy obsługi wyjątków dotyczących zadań):

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;
...

Wdrażanie nowych interfejsów klienta.

Usuń użycie GoogleApiClient i powiązane interfejsy (ConnectionCallbacks, OnConnectionFailedListener itp.) i zastąpić drugi Implementacje detektorów w nowych wersjach. Rzeczywiste metody zwykle mają takie same nazwy jak wcześniej, więc główna zmiana to podobnie jak w przykładzie poniżej.

Główna aktywność próbki warstwy danych Wear (wskazana w różnicach) w dniu GitHub) wdrożyliśmy na przykład interfejsu CapabilityApi.CapabilityListener. Teraz jednak implementacje głównych działań CapabilityClient.OnCapabilityChangedListener

Poniżej znajdziesz porównanie definicji klas.

Oto fragment kodu, który znajduje się przed użyciem wersji 11.8.0 Google Play usługi:

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

Oto fragment kodu używany po użyciu wersji 11.8.0 Google Play usługi:

Kotlin

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

Java

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

Usuń i dodaj detektory

Nowe obiekty klienta są przechowywane w pamięci podręcznej i współdzielone między instancjami GoogleApi, dlatego nie ma potrzeby utrzymywania elementu zmienne; są niedrogie i nie stracą słuchaczom.

Poniżej znajdziesz fragment zmienionej warstwy danych dotyczących Wear przykład:

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

Wysyłanie próśb o informacje za pomocą interfejsu Tasks API

Możesz też poprosić o informacje spoza listy detektorów, którzy aktualizują się do Twojej aplikacji, gdy nastąpi zmiana danych. W takich przypadkach użyj funkcji klienta, takiego jak DataClient, w połączeniu z interfejsem Tasks API oraz klasę wyniku (czyli Task<ResultType>).

Na przykład jak widać w warstwie danych z Wear przykładowej, możesz użyć interfejsu Tasks API, aby znajdź połączone węzły o dowolnych możliwościach:

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

Dodatkowy kod, który korzysta z interfejsów API do noszenia i Listy zadań, znajdziesz w Warstwa danych Wear przykład. To przykład wykorzystania ciężkich zadań poza wątki interfejsu użytkownika. lub w usłudze, pojawia się inna opcja. Oto przykład Jak zablokować zadanie i generować wyniki synchronicznie:

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