مزامنة البيانات

يوضّح هذا المستند كيفية مزامنة البيانات بين جهاز Wear OS وأحد الأجهزة الجوّالة.

إرسال البيانات ومزامنتها مباشرةً من الشبكة

أنشئ تطبيقات Wear OS للتواصل مباشرةً مع الشبكة. استخدِم واجهات برمجة التطبيقات نفسها التي تستخدمها لتطوير التطبيقات المتوافقة مع الأجهزة الجوّالة، مع الانتباه إلى بعض اختلافات Wear OS.

مزامنة البيانات باستخدام Wear OS Data Layer API

يعرِض DataClient واجهة برمجة تطبيقات للمكونات من أجل القراءة أو الكتابة في DataItem أو Asset.

من الممكن ضبط عناصر البيانات ومواد العرض بدون الاتصال بأي أجهزة. تتم مزامنتها عندما تتصل الأجهزة بالشبكة. وهذه البيانات خاصة بتطبيقك ولا يمكن لأحد الوصول إليها إلا من خلال تطبيقك على الأجهزة الأخرى.

  • تتم مزامنة DataItem على جميع الأجهزة في شبكة Wear OS. وتكون هذه الملفات صغيرة الحجم بشكل عام.

  • استخدِم Asset لنقل عنصر أكبر، مثل صورة. يتتبّع النظام مواد العرض التي سبق نقلها وينفّذ عملية إزالة تكرار تلقائيًا.

الاستماع إلى الأحداث في الخدمات

وسِّع فئة WearableListenerService. يدير النظام مراحل تطوير القاعدة WearableListenerService، ويرتبط بالخدمة عندما يحتاج إلى إرسال عناصر البيانات أو الرسائل، ويفك الارتباط بالخدمة عندما لا يكون هناك حاجة إلى إجراء أي عمل.

الاستماع إلى الأحداث في الأنشطة

نفِّذ واجهة OnDataChangedListener. استخدِم هذه الواجهة بدلاً من WearableListenerService عندما تريد الاستماع إلى التغييرات فقط عندما يستخدم المستخدم تطبيقك بشكل نشط.

نقل البيانات

لإرسال عناصر ثنائية كبيرة عبر بروتوكول النقل عبر البلوتوث، مثل تسجيل صوتي من جهاز آخر، يمكنك إرفاق Asset بعنصر بيانات ثم وضع عنصر البيانات في قاعدة بيانات النسخة المكرّرة.

تعالج مواد العرض تلقائيًا ميزة التخزين المؤقت للبيانات لمنع إعادة الإرسال والحفاظ على معدل نقل البيانات عبر البلوتوث. من الشائع أن يقوم تطبيق متوافق مع الأجهزة الجوّالة بتنزيل صورة وتصغيرها إلى حجم مناسب لعرضها على الجهاز القابل للارتداء وإرسالها إلى تطبيق الجهاز القابل للارتداء كمادة عرض. توضِّح الأمثلة التالية هذا النمط.

ملاحظة: على الرغم من أنّ حجم عناصر البيانات يقتصر نظريًا على 100 كيلوبايت، يمكن استخدام عناصر بيانات أكبر حجمًا عمليًا. بالنسبة إلى عناصر البيانات الأكبر حجمًا، عليك فصل البيانات حسب المسارات الفريدة وتجنُّب استخدام مسار واحد لجميع البيانات. يؤثر نقل مواد العرض الكبيرة في تجربة المستخدم في العديد من الحالات، لذا عليك اختبار تطبيقاتك للمساعدة في ضمان أدائها الجيد عند نقل مواد العرض الكبيرة.

نقل مادة عرض

أنشئ مادة العرض باستخدام إحدى طرق create...() في فئة Asset. حوِّل صورة نقطية إلى بث بايتات، ثم استخدِم الإجراء createFromBytes() لإنشاء مادة العرض، كما هو موضّح في المثال التالي.

KotlinJava
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:

KotlinJava
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:

KotlinJava
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 لرصد تغيير في مادة العرض واستخراجها:

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