Синхронизировать постоянные данные

В этом документе описывается, как синхронизировать данные между устройством Wear OS и портативным устройством.

Отправляйте и синхронизируйте данные прямо из сети

Создавайте приложения Wear OS для прямого взаимодействия с сетью . Используйте те же API-интерфейсы, которые вы используете для разработки мобильных устройств, но помните о некоторых различиях, специфичных для Wear OS.

Синхронизируйте данные с помощью API уровня данных Wear OS.

DataClient предоставляет компонентам API для чтения или записи в DataItem или Asset .

Можно устанавливать элементы данных и активы, не подключаясь к каким-либо устройствам. Они синхронизируются, когда устройства устанавливают сетевое соединение. Эти данные являются конфиденциальными для вашего приложения и доступны только вашему приложению на других устройствах.

  • DataItem синхронизируется на всех устройствах в сети Wear OS. Они, как правило, небольшого размера.

  • Используйте Asset для передачи более крупного объекта, например изображения. Система отслеживает, какие активы уже были переданы, и автоматически выполняет дедупликацию.

Слушайте события в сервисах

Расширьте класс WearableListenerService . Система управляет жизненным циклом базового WearableListenerService , привязываясь к сервису, когда ему необходимо отправлять элементы данных или сообщения, и отвязывая сервис, когда никаких действий не требуется.

Слушайте события в действиях

Реализуйте интерфейс OnDataChangedListener . Используйте этот интерфейс вместо WearableListenerService , если вы хотите прослушивать изменения только тогда, когда пользователь активно использует ваше приложение.

Перенос данных

Чтобы отправить большие двоичные объекты по каналу Bluetooth, например запись голоса с другого устройства, вы можете прикрепить Asset к элементу данных, а затем поместить элемент данных в реплицируемое хранилище данных.

Ресурсы автоматически кэшируют данные, чтобы предотвратить повторную передачу и сохранить пропускную способность Bluetooth. Обычно портативное приложение загружает изображение, сжимает его до подходящего размера для отображения на носимом устройстве и передает его в носимое приложение в качестве ресурса. Следующие примеры демонстрируют эту закономерность.

Примечание. Хотя размер элементов данных теоретически ограничен 100 КБ, на практике можно использовать элементы данных большего размера. Для более крупных элементов данных разделяйте данные по уникальным путям и избегайте использования одного пути для всех данных. Передача больших ресурсов во многих случаях влияет на удобство работы пользователей, поэтому тестируйте свои приложения, чтобы убедиться, что они работают хорошо при передаче больших ресурсов.

Передача актива

Создайте актив, используя один из методов create...() в классе Asset . Преобразуйте растровое изображение в поток байтов, а затем вызовите createFromBytes() чтобы создать ресурс, как показано в следующем примере.

Котлин

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

Затем прикрепите актив к элементу данных с помощью метода putAsset() в DataMap или PutDataRequest . Затем поместите элемент данных в хранилище данных с помощью метода putDataItem() , как показано в следующих примерах.

В следующем примере используется 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);

В следующем примере используется 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);

Получить активы

Когда ресурс создан, вы, вероятно, захотите прочитать и извлечь его на другой стороне соединения. Вот пример того, как реализовать обратный вызов для обнаружения изменения актива и извлечения актива:

Котлин

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

Дополнительные сведения см. в примере проекта DataLayer на GitHub.