W tym dokumencie opisano, jak zsynchronizować dane między urządzeniem z Wear OS a urządzeniem przenośnym.
Wysyłanie i synchronizowanie danych bezpośrednio z sieci
Twórz aplikacje na Wear OS, aby komunikować się bezpośrednio z siecią. Używaj tych samych interfejsów API, których używasz do tworzenia aplikacji mobilnych, ale pamiętaj o niektórych różnicach dotyczących Wear OS.
Synchronizacja danych za pomocą interfejsu Wear OS Data Layer API
DataClient
udostępnia interfejs API, który pozwala komponentom odczytywać lub zapisywać dane w DataItem
lub Asset
.
Elementy danych i zasoby można ustawiać bez łączenia z żadnymi urządzeniami. Synchronizowane są, gdy urządzenia nawiążą połączenie z internetem. Te dane są prywatne i dostępne tylko dla Twojej aplikacji na innych urządzeniach.
DataItem
jest synchronizowany na wszystkich urządzeniach w sieci Wear OS. Zwykle są one małe.Użyj
Asset
, aby przenieść większy obiekt, np. obraz. System śledzi, które zasoby zostały już przeniesione, i automatycznie wykonuje deduplikację.
Nasłuchiwanie zdarzeń w usługach
Rozwiń klasę WearableListenerService
. System zarządza cyklem życia bazy WearableListenerService
, łącząc ją z usługą, gdy musi wysłać elementy danych lub wiadomości, oraz odłączając ją od usługi, gdy nie jest potrzebna.
Nasłuchiwanie zdarzeń w działaniach
Zaimplementuj interfejs OnDataChangedListener
. Użyj tego interfejsu zamiast WearableListenerService
, gdy chcesz wykrywać zmiany tylko wtedy, gdy użytkownik aktywnie korzysta z aplikacji.
Przenoszenie danych
Aby wysłać duże obiekty binarne przez transport Bluetooth, takie jak nagranie głosowe z innego urządzenia, możesz dołączyć
Asset
do elementu danych, a następnie umieścić ten element w replikowanym magazynie danych.
Komponenty automatycznie obsługują buforowanie danych, aby zapobiec ich ponownemu przesyłaniu i zaoszczędzić przepustowość Bluetooth. Typowy schemat działania polega na tym, że aplikacja na urządzeniu mobilnym pobiera obraz, zmniejsza go do odpowiedniego rozmiaru do wyświetlania na urządzeniu noszonego i przekazuje go jako komponent. Ten wzorzec ilustrują poniższe przykłady.
Uwaga: chociaż teoretycznie rozmiar elementów danych jest ograniczony do 100 KB, w praktyce można używać większych elementów danych. W przypadku większych elementów danych rozdzielaj je według unikalnych ścieżek i nie używaj jednej ścieżki dla wszystkich danych. Przenoszenie dużych zasobów wpływa w wielu przypadkach na wrażenia użytkownika, dlatego przetestuj swoje aplikacje, aby upewnić się, że działają one prawidłowo podczas przesyłania dużych zasobów.
Przenoszenie zasobu
Utwórz zasób, korzystając z jednej z metod create...()
w klasie
Asset
.
Przekształć bitmapę w strumień bajtów, a następnie wywołaj funkcję
createFromBytes()
, aby utworzyć zasób, jak pokazano w tym przykładzie.
private fun createAssetFromBitmap(bitmap: Bitmap): Asset = ByteArrayOutputStream().let { byteStream -> bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream) Asset.createFromBytes(byteStream.toByteArray()) }
private static Asset createAssetFromBitmap(Bitmap bitmap) { final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream); return Asset.createFromBytes(byteStream.toByteArray()); }
Następnie dołącz zasób do elementu danych za pomocą metody putAsset()
w
DataMap
lub
PutDataRequest
. Następnie umieść element danych w magazynie danych, używając metody
putDataItem()
, jak pokazano w następujących przykładach.
Ten przykład używa PutDataRequest
:
val asset: Asset = BitmapFactory.decodeResource(resources, R.drawable.image).let { bitmap -> createAssetFromBitmap(bitmap) } val request: PutDataRequest = PutDataRequest.create("/image").apply { putAsset("profileImage", asset) } val putTask: Task<DataItem> = Wearable.getDataClient(context).putDataItem(request)
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); Asset asset = createAssetFromBitmap(bitmap); PutDataRequest request = PutDataRequest.create("/image"); request.putAsset("profileImage", asset); Task<DataItem> putTask = Wearable.getDataClient(context).putDataItem(request);
Ten przykład używa PutDataMapRequest
:
val asset: Asset = BitmapFactory.decodeResource(resources, R.drawable.image).let { bitmap -> createAssetFromBitmap(bitmap) } val request: PutDataRequest = PutDataMapRequest.create("/image").run { dataMap.putAsset("profileImage", asset) asPutDataRequest() } val putTask: Task<DataItem> = Wearable.getDataClient(context).putDataItem(request)
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); Asset asset = createAssetFromBitmap(bitmap); PutDataMapRequest dataMap = PutDataMapRequest.create("/image"); dataMap.getDataMap().putAsset("profileImage", asset); PutDataRequest request = dataMap.asPutDataRequest(); Task<DataItem> putTask = Wearable.getDataClient(context).putDataItem(request);
Odbieranie zasobów
Po utworzeniu zasobu prawdopodobnie będziesz chciał odczytać go i wyodrębnić po drugiej stronie połączenia. Oto przykład implementacji funkcji wywołania zwrotnego do wykrywania zmian zasobu i wyodrębniania zasobu:
override fun onDataChanged(dataEvents: DataEventBuffer) { dataEvents .filter { it.type == DataEvent.TYPE_CHANGED && it.dataItem.uri.path == "/image" } .forEach { event -> val bitmap: Bitmap? = DataMapItem.fromDataItem(event.dataItem) .dataMap.getAsset("profileImage") .let { asset -> loadBitmapFromAsset(asset) } // Do something with the bitmap } } fun loadBitmapFromAsset(asset: Asset): Bitmap? { // Convert asset into a file descriptor and block until it's ready val assetInputStream: InputStream? = Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset)) ?.inputStream return assetInputStream?.let { inputStream -> // Decode the stream into a bitmap BitmapFactory.decodeStream(inputStream) } ?: run { Log.w(TAG, "Requested an unknown Asset.") null } }
@Override public void onDataChanged(DataEventBuffer dataEvents) { for (DataEvent event : dataEvents) { if (event.getType() == DataEvent.TYPE_CHANGED && event.getDataItem().getUri().getPath().equals("/image")) { DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem()); Asset profileAsset = dataMapItem.getDataMap().getAsset("profileImage"); Bitmap bitmap = loadBitmapFromAsset(profileAsset); // Do something with the bitmap } } } public Bitmap loadBitmapFromAsset(Asset asset) { if (asset == null) { throw new IllegalArgumentException("Asset must be non-null"); } // Convert asset into a file descriptor and block until it's ready InputStream assetInputStream = Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset)) .getInputStream(); if (assetInputStream == null) { Log.w(TAG, "Requested an unknown Asset."); return null; } // Decode the stream into a bitmap return BitmapFactory.decodeStream(assetInputStream); }
Więcej informacji znajdziesz w przykładowym projekcie DataLayer na GitHubie.