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

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

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

פיתוח אפליקציות ל-Wear OS שמתקשרות ישירות עם הרשת. אפשר להשתמש באותם ממשקי 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() כדי ליצור את הנכס, כפי שמתואר בדוגמה הבאה.

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.