סנכרון נתונים

במאמר הזה מוסבר איך לסנכרן נתונים בין מכשיר Wear OS לבין מכשיר נייד.

שליחה וסנכרון של נתונים ישירות מהרשת

פיתוח אפליקציות ל-Wear OS שמתקשרות ישירות עם הרשת. משתמשים באותם ממשקי API שבהם משתמשים לפיתוח לאפליקציות לנייד, אבל צריך לזכור שיש כמה הבדלים ספציפיים ל-WearOS.

סנכרון נתונים באמצעות Wear OS Data Layer API

DataClient חושף API לרכיבים כדי לקרוא או לכתוב ל-DataItem או ל-Asset.

אפשר להגדיר פריטי נתונים ונכסים גם כשלא מחוברים למכשירים. הם מסונכרנים כשהמכשירים מתחברים לרשת. הנתונים האלה פרטיים לאפליקציה שלכם, ורק האפליקציה שלכם יכולה לגשת אליהם במכשירים אחרים.

  • DataItem מסונכרן בין כל המכשירים ברשת Wear OS. הם בדרך כלל קטנים.

  • אפשר להשתמש ב-Asset כדי להעביר אובייקט גדול יותר, כמו תמונה. המערכת עוקבת אחרי הנכסים שכבר הועברו ומבצעת הסרת כפילויות באופן אוטומטי.

האזנה לאירועים בשירותים

הארכת השיעור WearableListenerService. המערכת מנהלת את מחזור החיים של WearableListenerService הבסיסי, ומקשרת לשירות כשהיא צריכה לשלוח פריטי נתונים או הודעות, ומבטלת את הקישור לשירות כשאין צורך בפעולה.

האזנה לאירועים בפעילויות

מטמיעים את הממשק OnDataChangedListener. אפשר להשתמש בממשק הזה במקום ב-WearableListenerService כשרוצים להאזין לשינויים רק כשהמשתמש משתמש באפליקציה באופן פעיל.

העברת נתונים

כדי לשלוח אובייקטים בינאריים גדולים (BLOB) דרך פרוטוקול Bluetooth, כמו הקלטת קול ממכשיר אחר, אפשר לצרף Asset לפריט נתונים ואז להכניס את פריט הנתונים למאגר הנתונים המשוכפל.

הנכסים מטפלים אוטומטית בשמירת נתונים במטמון כדי למנוע שידור חוזר ולחסוך ברוחב הפס של Bluetooth. דפוס נפוץ הוא שאפליקציה לנייד מורידה תמונה, מצמצמת אותה לגודל מתאים לתצוגה במכשיר הלביש, ומעבירה אותה לאפליקציה למכשיר הלביש כנכס. הדוגמאות הבאות ממחישות את התבנית הזו.

הערה: למרות שהגודל של פריטי נתונים מוגבל באופן תיאורטי ל-100KB, בפועל אפשר להשתמש בפריטי נתונים גדולים יותר. בפריטי נתונים גדולים יותר, צריך להפריד את הנתונים לפי נתיבים ייחודיים ולא להשתמש בנתיב יחיד לכל הנתונים. העברה של נכסים גדולים משפיעה על חוויית המשתמש במקרים רבים, ולכן מומלץ לבדוק את האפליקציות כדי לוודא שהן פועלות בצורה טובה כשמעבירים נכסים גדולים.

העברת נכס

יוצרים את הנכס באמצעות אחת משיטות create...() במחלקה Asset. ממירים מפת סיביות לזרם בייטים ואז קוראים ל- createFromBytes() כדי ליצור את הנכס, כמו בדוגמה הבאה.

Kotlin

private fun createAssetFromBitmap(bitmap: Bitmap): Asset =
    ByteArrayOutputStream().let { byteStream ->
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream)
        Asset.createFromBytes(byteStream.toByteArray())
    }

Java

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:

Kotlin

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)

Java

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:

Kotlin

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)

Java

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

קבלת נכסים

כשיוצרים נכס, סביר להניח שתרצו לקרוא אותו ולחלץ אותו בצד השני של החיבור. דוגמה להטמעה של פונקציית הקריאה החוזרת כדי לזהות שינוי בנכס ולחלץ את הנכס:

Kotlin

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

Java

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