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

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

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

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

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

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

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

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

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

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

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

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

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

העברת נתונים

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

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

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

העברת נכס

יצירת הנכס באחת מהשיטות create...() ב- כיתה Asset. המרת מפת סיביות (bitmap) לשידור של בייטים ואז קריאה 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);

קבלת נכסים

כשיוצרים נכס, כדאי לקרוא ולחלץ אותו אותו בצד השני של החיבור. דוגמה לאופן שבו צריך ליישם את המדיניות קריאה חוזרת (callback) כדי לזהות שינוי בנכס ולחלץ את הנכס:

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.