כששולחים קריאה ל-Data Layer API, אפשר לקבל את הסטטוס של הקריאה כשהיא מסתיימת. אתם יכולים גם להאזין לאירועי נתונים שנובעים משינויים בנתונים שהאפליקציה שלכם מבצעת בכל מקום ברשת Wear OS by Google.
דוגמה לשימוש יעיל ב-Data Layer API מופיעה באפליקציה Android DataLayer Sample.
המתנה לסטטוס של קריאות לשכבת הנתונים
קריאות ל-Data Layer API – כמו קריאה באמצעות השיטה putDataItem של המחלקה DataClient – מחזירות לפעמים אובייקט Task<ResultType>. ברגע שאובייקט Task נוצר, הפעולה מתווספת לתור ברקע.
אם לא תבצעו פעולות נוספות אחרי זה, הפעולה תסתיים בסופו של דבר ללא התראה.
עם זאת, בדרך כלל רוצים לעשות משהו עם התוצאה אחרי שהפעולה מסתיימת, ולכן האובייקט Task מאפשר לכם להמתין לסטטוס התוצאה, באופן אסינכרוני או סינכרוני.
שיחות אסינכרוניות
אם הקוד שלכם פועל ב-thread הראשי של ממשק המשתמש, אל תבצעו קריאות חוסמות ל-Data Layer API. מריצים את הקריאות באופן אסינכרוני על ידי הוספת פונקציית קריאה חוזרת לאובייקט Task, שמופעלת כשהפעולה מסתיימת:
// Using Kotlin function references
task.addOnSuccessListener(::handleDataItem)
task.addOnFailureListener(::handleDataItemError)
task.addOnCompleteListener(::handleTaskComplete)
...
fun handleDataItem(dataItem: DataItem) { ... }
fun handleDataItemError(exception: Exception) { ... }
fun handleTaskComplete(task: Task<DataItem>) { ... }
אפשר לעיין בTask API כדי לראות אפשרויות נוספות, כולל שרשור של ביצוע משימות שונות.
שיחות סינכרוניות
אם הקוד שלכם פועל ב-thread נפרד של handler בשירות רקע, כמו ב-WearableListenerService, אין בעיה שהקריאות ייחסמו.
במקרה כזה, אפשר להתקשר אל Tasks.await() באובייקט Task, שחוסם עד שהבקשה מסתיימת ומחזיר אובייקט Result. אפשר לראות את זה בדוגמה הבאה.
הערה: אל תתקשרו למספר הזה כשאתם בשרשור הראשי.
try {
Tasks.await(dataItemTask).apply {
Log.d(TAG, "Data item set: $uri")
}
}
catch (e: ExecutionException) { ... }
catch (e: InterruptedException) { ... }
האזנה לאירועים בשכבת הנתונים
שכבת הנתונים מסנכרנת ושולחת נתונים בין המכשיר הנייד והמכשיר הלביש, ולכן בדרך כלל צריך להאזין לאירועים חשובים כמו יצירה של פריטי נתונים וקבלת הודעות.
יש שתי אפשרויות להאזנה לאירועים בשכבת הנתונים:
- יוצרים שירות שמרחיב את
WearableListenerService. - יוצרים פעילות או מחלקה שמטמיעות את הממשק
DataClient.OnDataChangedListener.
בשתי האפשרויות האלה, אתם מבטלים את שיטות הקריאה החוזרת של אירועי הנתונים עבור האירועים שאתם רוצים לטפל בהם.
הערה: כשבוחרים הטמעה של listener, חשוב לקחת בחשבון את השימוש בסוללה של האפליקציה. WearableListenerService רשום במניפסט של האפליקציה, ויכול להפעיל את האפליקציה אם היא לא פועלת כבר. אם אתם צריכים להאזין לאירועים רק כשהאפליקציה כבר פועלת, כמו במקרים רבים של אפליקציות אינטראקטיביות, אל תשתמשו ב-WearableListenerService. במקום זאת, צריך לרשום מעבד אירוע של שידור חי. לדוגמה, אפשר להשתמש בשיטה addListener של המחלקה DataClient. הפעולה הזו יכולה להפחית את העומס על המערכת ואת השימוש בסוללה.
שימוש ב-WearableListenerService
בדרך כלל יוצרים מופעים של WearableListenerService באפליקציות לנייד ובאפליקציות למכשירים לבישים. אבל אם אתם לא מעוניינים באירועי נתונים באחת מהאפליקציות, אתם לא צריכים להטמיע את השירות באפליקציה הזו.
לדוגמה, יכולה להיות אפליקציה לנייד שמגדירה ומקבלת אובייקטים של פריטי נתונים, ואפליקציה למכשיר לביש שמקשיבה לעדכונים האלה כדי לעדכן את ממשק המשתמש שלה. אפליקציית המכשיר הלביש אף פעם לא מעדכנת את פריטי הנתונים, ולכן אפליקציית המכשיר הנייד לא מאזינה לאירועי נתונים מאפליקציית המכשיר הלביש.
אלה חלק מהאירועים שאפשר להאזין להם באמצעות WearableListenerService:
-
onDataChanged(): בכל פעם שאובייקט של פריט נתונים נוצר, נמחק או משתנה, המערכת מפעילה את הקריאה החוזרת הזו בכל הצמתים המחוברים. -
onMessageReceived(): הודעה שנשלחת מצומת מפעילה את הקריאה החוזרת הזו בצומת היעד. -
onCapabilityChanged(): כשפונקציה שמופיעה בפרסום של מופע של האפליקציה שלכם הופכת לזמינה ברשת, האירוע הזה מפעיל את הקריאה החוזרת הזו. אם אתם מחפשים צומת בקרבת מקום, אתם יכולים לשלוח שאילתה לשיטהisNearby()של הצמתים שסופקו בקריאה החוזרת.
אפשר גם להאזין לאירועים מ-ChannelClient.ChannelCallback, כמו onChannelOpened().
כל האירועים הקודמים מופעלים בשרשור ברקע, ולא בשרשור הראשי.
כדי ליצור WearableListenerService, פועלים לפי השלבים הבאים:
- יוצרים מחלקה שמרחיבה את
WearableListenerService. - האזנה לאירועים שמעניינים אתכם, כמו
onDataChanged(). - מצהירים על מסנן Intent במניפסט של Android כדי להודיע למערכת על
WearableListenerService. ההצהרה הזו מאפשרת למערכת לקשור את השירות שלכם לפי הצורך.
בדוגמה הבאה אפשר לראות איך מטמיעים WearableListenerService:
class DataLayerListenerService : WearableListenerService() { override fun onDataChanged(dataEvents: DataEventBuffer) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "onDataChanged: $dataEvents") } // Loop through the events and send a message // to the node that created the data item. dataEvents .map { it.dataItem.uri } .forEach { uri -> // Get the node ID from the host value of the URI. val nodeId: String = uri.host!! // Set the data of the message to be the bytes of the URI. val payload: ByteArray = uri.toString().toByteArray() // Send the RPC. Wearable.getMessageClient(this) .sendMessage( nodeId, DATA_ITEM_RECEIVED_PATH, payload ) } } }
בקטע הבא מוסבר איך להשתמש במסנן כוונות עם מאזין כזה.
שימוש בפילטרים עם WearableListenerService
מסנן כוונות לדוגמה WearableListenerService שמוצגת בקטע הקודם יכול להיראות כך:
<service android:name=".snippets.datalayer.DataLayerListenerService" android:exported="true" tools:ignore="ExportedService" > <intent-filter> <action android:name="com.google.android.gms.wearable.DATA_CHANGED" /> <data android:scheme="wear" android:host="*" android:path="/start-activity" /> </intent-filter> </service>
מסנן הפעולות DATA_CHANGED מציין למערכת שהאפליקציה שלכם מתעניינת באירועים של שכבת הנתונים.
בדוגמה הזו, השעון מאזין לפריט הנתונים /start-activity והטלפון מאזין לתגובת ההודעה /data-item-received (DATA_ITEM_RECEIVED_PATH).
הכללים הרגילים להתאמת מסננים ב-Android חלים. אפשר לציין כמה שירותים בכל מניפסט, כמה מסנני כוונות בכל שירות, כמה פעולות בכל מסנן וכמה קטעי נתונים בכל מסנן. המסננים יכולים להתאים למארח עם תבנית wildcard או למארח ספציפי. כדי להתאים למארח עם תו כללי לחיפוש, משתמשים ב-host="*". כדי להתאים למארח ספציפי, מציינים host=<node_id>.
אפשר גם להתאים נתיב מילולי או קידומת נתיב. כדי לעשות את זה, צריך לציין תו כללי לחיפוש או מארח ספציפי. אחרת, המערכת מתעלמת מהנתיב שציינתם.
מידע נוסף על סוגי המסננים שנתמכים ב-Wear OS זמין במאמרי העזרה של ה-API בנושא WearableListenerService.
מידע נוסף על מסנני נתונים וכללי התאמה זמין במסמכי העזרה בנושא API של רכיב המניפסט <data>.
כשמתאימים מסנני כוונות, חשוב לזכור שני כללים:
- אם לא מציינים סכימה למסנן הכוונות, המערכת מתעלמת מכל שאר מאפייני ה-URI.
- אם לא מציינים מארח למסנן, המערכת מתעלמת מכל מאפייני הנתיב.
שימוש במאזין בזמן אמת
אם האפליקציה שלכם מתעניינת רק באירועים של שכבת הנתונים כשהמשתמש נמצא באינטראקציה עם האפליקציה, יכול להיות שהיא לא צריכה שירות שפועל לאורך זמן כדי לטפל בכל שינוי בנתונים. במקרה כזה, אפשר להאזין לאירועים בפעילות על ידי הטמעה של אחד או יותר מהממשקים הבאים:
DataClient.OnDataChangedListenerMessageClient.OnMessageReceivedListenerCapabilityClient.OnCapabilityChangedListenerChannelClient.ChannelCallback
כדי ליצור פעילות שמקשיבה לאירועי נתונים, פועלים לפי השלבים הבאים:
- מטמיעים את הממשקים הנדרשים.
- בשיטה
onCreate()או בשיטהonResume(), קוראים ל-Wearable.getDataClient(this).addListener(), ל-MessageClient.addListener(), ל-CapabilityClient.addListener()או ל-ChannelClient.registerChannelCallback()כדי להודיע ל-Google Play Services שהפעילות שלכם מתעניינת באירועים של שכבת הנתונים. - ב-
onStop()או ב-onPause(), מבטלים את הרישום של כל מאזין באמצעותDataClient.removeListener(),MessageClient.removeListener(),CapabilityClient.removeListener()אוChannelClient.unregisterChannelCallback(). - אם פעילות מסוימת צריכה לקבל רק אירועים עם קידומת נתיב ספציפית, מוסיפים מאזין עם מסנן קידומת כדי לקבל רק נתונים שרלוונטיים למצב הנוכחי של האפליקציה.
- מטמיעים את
onDataChanged(),onMessageReceived(),onCapabilityChanged()או שיטות מתוךChannelClient.ChannelCallback, בהתאם לממשקים שהטמעתם. ה-methods האלה נקראות ב-thread הראשי, או שאפשר לצייןLooperבהתאמה אישית באמצעותWearableOptions.
דוגמה להטמעה של DataClient.OnDataChangedListener:
class MainActivity : Activity(), DataClient.OnDataChangedListener { public override fun onResume() { super.onResume() Wearable.getDataClient(this).addListener(this) } override fun onPause() { super.onPause() Wearable.getDataClient(this).removeListener(this) } override fun onDataChanged(dataEvents: DataEventBuffer) { dataEvents.forEach { event -> if (event.type == DataEvent.TYPE_DELETED) { Log.d(TAG, "DataItem deleted: " + event.dataItem.uri) } else if (event.type == DataEvent.TYPE_CHANGED) { Log.d(TAG, "DataItem changed: " + event.dataItem.uri) } } } }
זהירות: לפני שמשתמשים ב-Wearable Data Layer API, צריך לבדוק שהוא זמין במכשיר. אחרת, תתרחש חריגה. משתמשים במחלקה
GoogleApiAvailability, כפי שהיא מוטמעת ב-Horologist.
שימוש בפילטרים עם מאזינים בזמן אמת
כמו שצוין קודם, בדיוק כמו שאפשר להגדיר מסנני Intent לאובייקטים של WearableListenerService שמבוססים על מניפסט, אפשר להשתמש במסנני Intent כשרושמים מאזין פעיל דרך Wearable API. אותם כללים חלים גם על מאזינים בשידור חי שמבוססים על API וגם על מאזינים שמבוססים על מניפסט.
דפוס נפוץ הוא לרשום listener עם נתיב ספציפי או קידומת נתיב בשיטת onResume() של פעילות, ואז להסיר את ה-listener בשיטת onPause() של הפעילות. הטמעה של פונקציות event listener באופן הזה מאפשרת לאפליקציה לקבל אירועים בצורה סלקטיבית יותר, וכך לשפר את העיצוב והיעילות שלה.