네트워크와 직접 통신하는 Wear OS 앱을 빌드합니다. 모바일 개발에 사용하는 것과 동일한 API를 사용하되 몇 가지 Wear OS만의 차이점을 염두에 두세요.
Wear OS Data Layer API를 사용하여 데이터 동기화
DataClient는 구성요소가 DataItem 또는 Asset를 읽거나 여기에 쓸 수 있는 API를 노출합니다.
기기에 연결되지 않은 상태에서 데이터 항목과 애셋을 설정할 수 있습니다.
기기가 네트워크 연결을 설정하면 동기화됩니다. 이 데이터는 앱에서만 사용할 수 있으며 다른 기기의 앱에서만 액세스할 수 있습니다.
DataItem는 Wear OS 네트워크의 모든 기기에서 동기화됩니다.
데이터 항목은 일반적으로 크기가 작습니다.
Asset를 사용하여 이미지와 같이 더 큰 객체를 전송합니다. 시스템은 이미 전송된 애셋을 추적하고 자동으로 중복 삭제를 실행합니다.
서비스에서 이벤트 수신 대기
WearableListenerService 클래스를 확장합니다. 시스템은 기본 WearableListenerService의 수명 주기를 관리하며, 데이터 항목이나 메시지를 전송해야 하면 서비스에 바인딩하고 필요한 작업이 없으면 서비스 바인딩을 해제합니다.
활동에서 이벤트 수신 대기
OnDataChangedListener 인터페이스를 구현합니다. 사용자가 앱을 적극적으로 사용하는 경우에만 변경사항을 수신 대기하려면 WearableListenerService 대신 이 인터페이스를 사용하세요.
데이터 전송
블루투스 전송을 통해 다른 기기의 음성 녹음 파일과 같은 바이너리 대형 객체를 전송하려면 Asset을 데이터 항목에 연결하고 이 데이터 항목을 복제된 데이터 스토어에 넣으면 됩니다.
재전송을 방지하고 블루투스 대역폭을 보존하기 위해 애셋은 데이터 캐싱을 자동으로 처리합니다.
일반적인 패턴은 휴대기기 앱이 이미지를 다운로드하고, 웨어러블에 표시하기 위한 적절한 크기로 축소한 다음, 웨어러블 앱에 애셋으로 전송하는 것입니다. 다음 예는 이 패턴을 보여줍니다.
참고: 데이터 항목의 크기는 이론적으로 100KB로 제한되지만 실제로는 더 큰 데이터 항목을 사용할 수 있습니다. 큰 데이터 항목의 경우 고유한 경로로 데이터를 구분하고 모든 데이터에 단일 경로를 사용하지 않아야 합니다. 대용량 애셋을 전송하면 대부분의 경우 사용자 환경에 영향을 미치므로 앱을 테스트하여 대용량 애셋을 전송할 때 성능이 저하되지 않는지 확인할 수 있습니다.
애셋 전송
Asset 클래스의 create...() 메서드 중 하나를 사용하여 애셋을 만듭니다.
비트맵을 바이트 스트림으로 변환한 후 다음 샘플과 같이 createFromBytes()를 호출하여 애셋을 만듭니다.
애셋이 생성되면 연결의 다른 쪽에서 애셋을 읽고 추출해야 할 수 있습니다. 다음은 애셋 변경을 감지하고 애셋을 추출하기 위해 콜백을 구현하는 방법의 예입니다.
Kotlin
overridefunonDataChanged(dataEvents:DataEventBuffer){dataEvents.filter{it.type==DataEvent.TYPE_CHANGED && it.dataItem.uri.path=="/image"}.forEach{event->
valbitmap:Bitmap? =DataMapItem.fromDataItem(event.dataItem).dataMap.getAsset("profileImage").let{asset->loadBitmapFromAsset(asset)}// Do something with the bitmap}}funloadBitmapFromAsset(asset:Asset):Bitmap? {// Convert asset into a file descriptor and block until it's readyvalassetInputStream:InputStream? =Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset))?.inputStreamreturnassetInputStream?.let{inputStream->
// Decode the stream into a bitmapBitmapFactory.decodeStream(inputStream)}?:run{Log.w(TAG,"Requested an unknown Asset.")null}}
자바
@OverridepublicvoidonDataChanged(DataEventBufferdataEvents){for(DataEventevent:dataEvents){if(event.getType()==DataEvent.TYPE_CHANGED&&
event.getDataItem().getUri().getPath().equals("/image")){DataMapItemdataMapItem=DataMapItem.fromDataItem(event.getDataItem());AssetprofileAsset=dataMapItem.getDataMap().getAsset("profileImage");Bitmapbitmap=loadBitmapFromAsset(profileAsset);// Do something with the bitmap}}}publicBitmaploadBitmapFromAsset(Assetasset){if(asset==null){thrownewIllegalArgumentException("Asset must be non-null");}// Convert asset into a file descriptor and block until it's readyInputStreamassetInputStream=Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset)).getInputStream();if(assetInputStream==null){Log.w(TAG,"Requested an unknown Asset.");returnnull;}// Decode the stream into a bitmapreturnBitmapFactory.decodeStream(assetInputStream);}
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-08-30(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-08-30(UTC)"],[],[],null,["This document describes how to synchronize data between a Wear OS device and a\nhandheld device.\n\nSend and sync data directly from the network\n\nBuild Wear OS apps to [communicate directly with the network](/training/wearables/data-layer/network-access). Use the same\nAPIs that you use for mobile development, but keep some Wear-OS-specific\ndifferences in mind.\n\nSynchronize data using the Wear OS Data Layer API\n\nA `DataClient` exposes an API for components to read or write to a `DataItem` or\n`Asset`.\n| **Note:** The class is meant to transfer data and not serve as a storage mechanism. Create your own copy of the data that your app can access, such as in a [Room\n| database](/training/data-storage/room).\n\nIt's possible to set data items and assets while not connected to any devices.\nThey're synchronized when the devices establish a network connection. This data\nis private to your app and is only accessible to your app on other devices.\n\n- A `DataItem` is synchronized across all devices in a Wear OS network.\n They're generally small in size.\n\n | **Note:** When an app is uninstalled on the phone, data items and assets are reset.\n- Use an `Asset` to transfer a larger object, such as an image. The system\n keeps track of which assets have already been transferred and performs\n deduplication automatically.\n\nListen for events in services\n\nExtend the [`WearableListenerService`](https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService) class. The system manages the\nlifecycle of the base `WearableListenerService`, binding to the service when it\nneeds to send data items or messages and unbinding the service when no work is\nneeded.\n\nListen for events in activities\n\nImplement the [`OnDataChangedListener`](https://developers.google.com/android/reference/com/google/android/gms/wearable/DataClient.OnDataChangedListener) interface. Use this interface instead\nof a `WearableListenerService` when you want to listen for changes only when the\nuser is actively using your app.\n\nTransfer data\n\nTo send binary large objects over the Bluetooth transport, such as a voice recording\nfrom another device, you can attach an\n[`Asset`](https://developers.google.com/android/reference/com/google/android/gms/wearable/Asset) to a data item and then put the data item into the replicated datastore.\n|\n| **Note:** The Data Layer API can send messages and synchronize data only with Android phones or\n| Wear OS watches. If a Wear OS device is paired with an iOS device, the Data Layer\n| API won't work.\n|\n|\n| For this reason, don't use the Data Layer API as the primary way to\n| communicate with a network. Instead, follow the same pattern in your Wear app as in a\n| mobile app---with some minor differences, as described in\n| [Network access and sync on Wear OS](/training/wearables/data-layer/network-access).\n\nAssets automatically handle caching of data to prevent retransmission and\nto conserve Bluetooth bandwidth.\nA common pattern is for a handheld app to download an image, shrink it to an appropriate size\nfor display on the wearable, and transmit it to the wearable app as an asset. The following examples\ndemonstrate this pattern.\n\n\n**Note:** Although the size of data items is theoretically limited to 100 KB, in practice larger data items can be used. For\nlarger data items, separate data by unique paths and avoid\nusing a single path for all data. Transferring large assets affects the user experience in many\ncases, so test your apps to help ensure that they perform well when transferring large assets.\n\nTransfer an asset\n\nCreate the asset using one of the `create...()` methods in the\n[`Asset`](https://developers.google.com/android/reference/com/google/android/gms/wearable/Asset.html) class.\nConvert a bitmap to a byte stream and then call\n[`createFromBytes()`](https://developers.google.com/android/reference/com/google/android/gms/wearable/Asset.html#createFromBytes(byte[]))\nto create the asset, as shown in the following sample. \n\nKotlin \n\n```kotlin\nprivate fun createAssetFromBitmap(bitmap: Bitmap): Asset =\n ByteArrayOutputStream().let { byteStream -\u003e\n bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream)\n Asset.createFromBytes(byteStream.toByteArray())\n }\n```\n\nJava \n\n```java\nprivate static Asset createAssetFromBitmap(Bitmap bitmap) {\n final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();\n bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream);\n return Asset.createFromBytes(byteStream.toByteArray());\n}\n```\n\nNext, attach the asset to a data item with the `putAsset()` method in\n[`DataMap`](https://developers.google.com/android/reference/com/google/android/gms/wearable/DataMap.html) or\n[`PutDataRequest`](https://developers.google.com/android/reference/com/google/android/gms/wearable/PutDataRequest.html). Then put the data item into the datastore using the\n[`putDataItem()`](https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)) method, as shown in the following samples.\n\nThe following sample uses `PutDataRequest`: \n\nKotlin \n\n```kotlin\nval asset: Asset = BitmapFactory.decodeResource(resources, R.drawable.image).let { bitmap -\u003e\n createAssetFromBitmap(bitmap)\n}\nval request: PutDataRequest = PutDataRequest.create(\"/image\").apply {\n putAsset(\"profileImage\", asset)\n}\nval putTask: Task\u003cDataItem\u003e = Wearable.getDataClient(context).putDataItem(request)\n```\n\nJava \n\n```java\nBitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);\nAsset asset = createAssetFromBitmap(bitmap);\nPutDataRequest request = PutDataRequest.create(\"/image\");\nrequest.putAsset(\"profileImage\", asset);\nTask\u003cDataItem\u003e putTask = Wearable.getDataClient(context).putDataItem(request);\n```\n\n\u003cbr /\u003e\n\nThe following sample uses `PutDataMapRequest`: \n\nKotlin \n\n```kotlin\nval asset: Asset = BitmapFactory.decodeResource(resources, R.drawable.image).let { bitmap -\u003e\n createAssetFromBitmap(bitmap)\n}\nval request: PutDataRequest = PutDataMapRequest.create(\"/image\").run {\n dataMap.putAsset(\"profileImage\", asset)\n asPutDataRequest()\n}\nval putTask: Task\u003cDataItem\u003e = Wearable.getDataClient(context).putDataItem(request)\n```\n\nJava \n\n```java\nBitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);\nAsset asset = createAssetFromBitmap(bitmap);\nPutDataMapRequest dataMap = PutDataMapRequest.create(\"/image\");\ndataMap.getDataMap().putAsset(\"profileImage\", asset);\nPutDataRequest request = dataMap.asPutDataRequest();\nTask\u003cDataItem\u003e putTask = Wearable.getDataClient(context).putDataItem(request);\n```\n\n\u003cbr /\u003e\n\nReceive assets\n\n\nWhen an asset is created, you probably want to read and extract\nit on other side of the connection. Here's an example of how to implement the\ncallback to detect an asset change and extract the asset: \n\nKotlin \n\n```kotlin\noverride fun onDataChanged(dataEvents: DataEventBuffer) {\n dataEvents\n .filter { it.type == DataEvent.TYPE_CHANGED && it.dataItem.uri.path == \"/image\" }\n .forEach { event -\u003e\n val bitmap: Bitmap? = DataMapItem.fromDataItem(event.dataItem)\n .dataMap.getAsset(\"profileImage\")\n .let { asset -\u003e loadBitmapFromAsset(asset) }\n // Do something with the bitmap\n }\n}\n\nfun loadBitmapFromAsset(asset: Asset): Bitmap? {\n // Convert asset into a file descriptor and block until it's ready\n val assetInputStream: InputStream? =\n Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset))\n ?.inputStream\n\n return assetInputStream?.let { inputStream -\u003e\n // Decode the stream into a bitmap\n BitmapFactory.decodeStream(inputStream)\n } ?: run {\n Log.w(TAG, \"Requested an unknown Asset.\")\n null\n }\n}\n```\n\nJava \n\n```java\n@Override\npublic void onDataChanged(DataEventBuffer dataEvents) {\n for (DataEvent event : dataEvents) {\n if (event.getType() == DataEvent.TYPE_CHANGED &&\n event.getDataItem().getUri().getPath().equals(\"/image\")) {\n DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());\n Asset profileAsset = dataMapItem.getDataMap().getAsset(\"profileImage\");\n Bitmap bitmap = loadBitmapFromAsset(profileAsset);\n // Do something with the bitmap\n }\n }\n}\n\npublic Bitmap loadBitmapFromAsset(Asset asset) {\n if (asset == null) {\n throw new IllegalArgumentException(\"Asset must be non-null\");\n }\n // Convert asset into a file descriptor and block until it's ready\n InputStream assetInputStream =\n Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset))\n .getInputStream();\n if (assetInputStream == null) {\n Log.w(TAG, \"Requested an unknown Asset.\");\n return null;\n }\n // Decode the stream into a bitmap\n return BitmapFactory.decodeStream(assetInputStream);\n}\n```\n\nFor more information, see the [DataLayer sample project](https://github.com/android/wear-os-samples/tree/main/DataLayer) on GitHub."]]