همگام سازی داده های پایدار

این سند نحوه همگام سازی داده ها را بین یک دستگاه Wear OS و یک دستگاه دستی شرح می دهد.

ارسال و همگام سازی داده ها به طور مستقیم از شبکه

برنامه‌های Wear OS را بسازید تا مستقیماً با شبکه ارتباط برقرار کنید . از همان API هایی استفاده کنید که برای توسعه موبایل استفاده می کنید، اما برخی از تفاوت های خاص Wear-OS را در نظر داشته باشید.

داده ها را با استفاده از Wear OS Data Layer API همگام سازی کنید

یک DataClient یک API برای خواندن یا نوشتن اجزا در یک DataItem یا Asset نمایش می دهد.

تنظیم اقلام و دارایی های داده در حالی که به هیچ دستگاهی متصل نیستید امکان پذیر است. هنگامی که دستگاه ها اتصال شبکه برقرار می کنند، همگام می شوند. این داده ها برای برنامه شما خصوصی هستند و فقط برای برنامه شما در دستگاه های دیگر قابل دسترسی هستند.

  • یک DataItem در تمام دستگاه‌های یک شبکه Wear OS همگام‌سازی می‌شود. آنها معمولاً اندازه کوچکی دارند.

  • از یک Asset برای انتقال یک شی بزرگتر مانند یک تصویر استفاده کنید. این سیستم پیگیری می کند که کدام دارایی قبلاً منتقل شده است و به طور خودکار حذف مجدد را انجام می دهد.

به رویدادهای خدمات گوش دهید

کلاس WearableListenerService را گسترش دهید. این سیستم چرخه حیات پایگاه WearableListenerService را مدیریت می‌کند، در صورت نیاز به ارسال اقلام داده یا پیام، به سرویس متصل می‌شود و زمانی که نیازی به کاری نیست، سرویس را لغو پیوند می‌کند.

به رویدادها در فعالیت ها گوش دهید

رابط OnDataChangedListener را پیاده سازی کنید. زمانی که می خواهید تغییرات را تنها زمانی که کاربر به طور فعال از برنامه شما استفاده می کند گوش دهید، از این رابط به جای WearableListenerService استفاده کنید.

انتقال داده ها

برای ارسال اشیاء بزرگ باینری از طریق انتقال بلوتوث، مانند ضبط صدا از دستگاه دیگر، می‌توانید یک Asset به یک مورد داده متصل کنید و سپس مورد داده را در ذخیره‌گاه داده تکراری قرار دهید.

دارایی ها به طور خودکار ذخیره داده ها را برای جلوگیری از ارسال مجدد و حفظ پهنای باند بلوتوث مدیریت می کنند. یک الگوی رایج این است که یک برنامه دستی یک تصویر را بارگیری می کند، آن را به اندازه مناسب برای نمایش در پوشیدنی کوچک می کند و آن را به عنوان دارایی به برنامه پوشیدنی منتقل می کند. مثال های زیر این الگو را نشان می دهند.

توجه: اگرچه اندازه اقلام داده از نظر تئوری به 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() مانند نمونه های زیر، آیتم داده را در datastore قرار دهید.

نمونه زیر از 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);

دریافت دارایی

هنگامی که یک دارایی ایجاد می شود، احتمالاً می خواهید آن را در طرف دیگر اتصال بخوانید و استخراج کنید. در اینجا مثالی از نحوه اجرای callback برای تشخیص تغییر دارایی و استخراج دارایی آورده شده است:

کاتلین

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 را ببینید.