عند إجراء طلب إلى Data Layer API، يمكنك تلقّي حالة الطلب عند اكتماله. يمكنك أيضًا الاستماع إلى أحداث البيانات الناتجة عن تغييرات البيانات التي يجريها تطبيقك في أي مكان على شبكة Wear OS من Google.
للاطّلاع على مثال حول كيفية استخدام واجهة برمجة التطبيقات Data Layer API بفعالية، يمكنك الرجوع إلى تطبيق Android DataLayer Sample
الانتظار إلى حين ظهور حالة طلبات Data Layer
تعرض أحيانًا الطلبات إلى واجهة برمجة التطبيقات Data Layer API، مثل طلب باستخدام طريقة putDataItem لفئة
DataClient، كائن Task<ResultType>. فور إنشاء كائن Task، يتم وضع العملية في قائمة الانتظار في الخلفية.
إذا لم تتّخذ أي إجراء آخر بعد ذلك، تكتمل العملية في النهاية بدون إشعارك.
ومع ذلك، من المعتاد أن تتّخذ إجراءً بشأن النتيجة بعد اكتمال العملية، لذا يتيح لك كائن Task انتظار حالة النتيجة، إما بشكل غير متزامن أو بشكل متزامن.
الطلبات غير المتزامنة
إذا كان الرمز البرمجي قيد التشغيل على سلسلة واجهة المستخدم الرئيسية، لا تُجرِ طلبات حظر إلى واجهة برمجة التطبيقات Data Layer API واستخدِم كوروتينًا لاستدعاء putDataItem:
private suspend fun Context.sendDataAsync(count: Int) { try { val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run { dataMap.putInt("count_key", count) asPutDataRequest() } val dataItem = Wearable.getDataClient(this).putDataItem(putDataReq).await() handleDataItem(dataItem) } catch (e: Exception) { handleDataItemError(e) } finally { handleTaskComplete() } } private fun handleDataItem(dataItem: DataItem) { } private fun handleDataItemError(exception: Exception) { } private fun handleTaskComplete() { }
يمكنك الاطّلاع على Task API لمعرفة الاحتمالات الأخرى، بما في ذلك ربط تنفيذ مهام مختلفة.
الطلبات المتزامنة
إذا كان الرمز البرمجي قيد التشغيل على سلسلة تعليمات معالج منفصلة في خدمة تُشغَّل في الخلفية، مثل WearableListenerService، استخدِم runBlocking لإجراء طلب حظر إلى putDataItem.
ملاحظة: لا تستدعِ هذا الرمز البرمجي أثناء استخدام سلسلة التعليمات الرئيسية.
private fun Context.sendDataSync(count: Int) = runBlocking { val putDataReq = PutDataMapRequest.create("/count").run { dataMap.putInt("count_key", count) asPutDataRequest() } try { val result = Wearable.getDataClient(this@sendDataSync) .putDataItem(putDataReq) .await() // Logic for success } catch (e: Exception) { // Handle failure } }
الاستماع إلى أحداث Data Layer
بما أنّ طبقة البيانات تُزامِن البيانات وترسلها بين الأجهزة المحمولة والأجهزة القابلة للارتداء، عليك عادةً الاستماع إلى الأحداث المهمة، مثل إنشاء عناصر البيانات وتلقّي الرسائل.
للاستماع إلى أحداث طبقة البيانات، لديك خياران:
- إنشاء خدمة توسّع
WearableListenerService. - إنشاء نشاط أو فئة تنفّذ واجهة
DataClient.OnDataChangedListener
باستخدام أي من هذين الخيارَين، يمكنك إلغاء طرق معاودة الاتصال بحدث البيانات للأحداث التي تهمّك معالجتها.
ملاحظة: ضَع في اعتبارك مدى استهلاك تطبيقك للبطارية عند اختيار عملية تنفيذ المستمع. يتم تسجيل WearableListenerService في بيان التطبيق ويمكنه تشغيل التطبيق إذا لم يكن قيد التشغيل بعد. إذا كنت بحاجة فقط إلى الاستماع إلى الأحداث عندما يكون تطبيقك قيد التشغيل، وهو ما يحدث غالبًا مع التطبيقات التفاعلية، لا تستخدِم WearableListenerService. بدلاً من ذلك، سجِّل مستمعًا مباشرًا. على سبيل المثال، استخدِم طريقة addListener لفئة
DataClient. يمكن أن يؤدي ذلك إلى تقليل الحمل على النظام وتقليل استهلاك البطارية.
استخدام WearableListenerService
عادةً ما تنشئ مثيلات من WearableListenerService في كلّ من تطبيقات الأجهزة القابلة للارتداء والأجهزة المحمولة. ومع ذلك، إذا لم تكن مهتمًا بأحداث البيانات في أحد التطبيقَين، لن تحتاج إلى تنفيذ الخدمة في هذا التطبيق.
على سبيل المثال، يمكنك استخدام تطبيق جهاز محمول يضبط كائنات عناصر البيانات ويحصل عليها وتطبيق مخصّص لجهاز قابل للارتداء يستمع إلى هذه التعديلات لتعديل واجهة المستخدم. لا يعدّل تطبيق مخصّص لجهاز قابل للارتداء أيًا من عناصر البيانات، لذا لا يستمع تطبيق الجهاز المحمول إلى أي أحداث بيانات من تطبيق مخصّص لجهاز قابل للارتداء.
في ما يلي بعض الأحداث التي يمكنك الاستماع إليها باستخدام WearableListenerService:
onDataChanged(): كلما تم إنشاء كائن عنصر بيانات أو حذفه أو تغييره، يؤدي النظام إلى تشغيل معاودة الاتصال هذه على جميع العُقد المتصلة.onMessageReceived(): تؤدي رسالة مرسَلة من إحدى العُقد إلى تشغيل معاودة الاتصال هذه على العُقدة المستهدَفة.onCapabilityChanged(): عندما تصبح إمكانية يعلن عنها مثيل من تطبيقك متاحة على الشبكة، يؤدي هذا الحدث إلى تشغيل معاودة الاتصال هذه. إذا كنت تبحث عن عُقدة قريبة، يمكنك طلب طريقة الـisNearby()للعُقد المتوفّرة في معاودة الاتصال.
يمكنك أيضًا الاستماع إلى الأحداث من ChannelClient.ChannelCallback، مثل
onChannelOpened().
يتم تنفيذ جميع الأحداث السابقة في سلسلة تعليمات خلفية، وليس على سلسلة التعليمات الرئيسية.
لإنشاء WearableListenerService، اتّبِع الخطوات التالية:
- أنشئ فئة توسّع
WearableListenerService. - استمع إلى الأحداث التي تهمّك، مثل
onDataChanged(). - أعلِن عن تعبير intent filter في بيان 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 ) } } }
يوضّح القسم التالي كيفية استخدام تعبير intent filter مع هذا المستمع.
استخدام الفلاتر مع WearableListenerService
قد يبدو تعبير intent filter لمثال 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. يمكنك تحديد خدمات متعددة لكل بيان، وفلاتر intent filter متعددة لكل خدمة، وإجراءات متعددة لكل فلتر، ومقاطع بيانات متعددة لكل فلتر. يمكن أن تتطابق الفلاتر مع مضيف حرف بدل أو مضيف معيّن. للمطابقة مع مضيف حرف بدل، استخدِم host="*". للمطابقة مع مضيف معيّن، حدِّد host=<node_id>.
يمكنك أيضًا مطابقة مسار حرفي أو بادئة مسار. لإجراء ذلك، عليك تحديد حرف بدل أو مضيف معيّن. بخلاف ذلك، يتجاهل النظام المسار الذي تحدّده.
لمزيد من المعلومات عن أنواع الفلاتر التي يتيحها Wear OS، يمكنك الاطّلاع على مستندات مرجع واجهة برمجة التطبيقات لـ WearableListenerService.
لمزيد من المعلومات عن فلاتر البيانات وقواعد المطابقة، يمكنك الاطّلاع على مستندات مرجع واجهة برمجة التطبيقات
لعنصر البيان <data>.
عند مطابقة فلاتر intent filter، ضَع في اعتبارك قاعدتَين مهمتَين:
- إذا لم يتم تحديد أي مخطط لفلتر intent filter، يتجاهل النظام جميع سمات URI الأخرى.
- إذا لم يتم تحديد أي مضيف للفلتر، يتجاهل النظام جميع سمات المسار.
استخدام مستمع مباشر
إذا كان تطبيقك يهتم فقط بأحداث طبقة البيانات عندما يتفاعل المستخدم مع التطبيق، قد لا يحتاج إلى خدمة طويلة الأمد لمعالجة كل تغيير في البيانات. في هذه الحالة، يمكنك الاستماع إلى الأحداث في نشاط.
للحصول على نهج أكثر وضوحًا وأمانًا، استخدِم مراقب دورة الحياة. باستخدام مراقب دورة الحياة، يمكنك نقل منطق التسجيل من LifecycleResumeEvent للنشاط إلى فئة منفصلة وقابلة لإعادة الاستخدام تنفّذ DefaultLifecycleObserver.
يحافظ هذا النهج على بساطة النشاط ويمنع الأخطاء الشائعة، مثل نسيان إلغاء تسجيل المستمع.
1. إنشاء مستمع مدرِك لدورة الحياة
تغلّف هذه الفئة DataClient.OnDataChangedListener وتدير تلقائيًا
اشتراكها الخاص استنادًا إلى دورة حياة النشاط.
class WearDataLayerObserver( private val dataClient: DataClient, private val onDataReceived: (DataEventBuffer) -> Unit ) : DefaultLifecycleObserver, DataClient.OnDataChangedListener { // Implementation of the DataClient listener override fun onDataChanged(dataEvents: DataEventBuffer) { onDataReceived(dataEvents) } // Automatically register when the Activity starts override fun onResume(owner: LifecycleOwner) { dataClient.addListener(this) } // Automatically unregister when the Activity pauses override fun onPause(owner: LifecycleOwner) { dataClient.removeListener(this) } }
2. الاستخدام في نشاطك
الآن، لا يحتاج نشاطك إلى استخدام LifecycleResumeEvent أو
onPause لواجهة برمجة التطبيقات Wear API. يمكنك تسجيل المراقب مرة واحدة في LaunchedEvent (أو onCreate).
class DataLayerLifecycleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val dataClient = Wearable.getDataClient(this) // Create the observer and link it to the activity's lifecycle val wearObserver = WearDataLayerObserver(dataClient) { dataEvents -> handleDataEvents(dataEvents) } lifecycle.addObserver(wearObserver) } private fun handleDataEvents(dataEvents: DataEventBuffer) { // ... filter and process events ... } }
أسباب أفضلية هذا النهج:
- نشاط أكثر وضوحًا: يمكنك إزالة الرموز البرمجية المتكررة من طرق مراحل النشاط.
- الأمان: يساعد
DefaultLifecycleObserverفي التحقّق من إزالة المستمع حتى إذا تم تدمير النشاط بشكل غير متوقّع، ما يمنع تسرّب الذاكرة. - سهولة إعادة الاستخدام: يمكنك ربط
WearDataLayerObserverبأي نشاط أو دالة مركّبة بدون إعادة كتابة منطق التسجيل. - الفصل: يتم فصل منطق وقت الاستماع عن منطق الإجراءات التي يجب اتّخاذها بشأن البيانات.
استخدام الفلاتر مع المستمعين المباشرين
كما ذكرنا سابقًا، يمكنك استخدام فلاتر intent filter
عند تسجيل مستمع مباشر من خلال Wearable API، تمامًا كما يمكنك تحديد فلاتر intent filter لكائنات
المستندة إلى البيان WearableListenerService. تنطبق القواعد نفسها على كلّ من المستمعين المباشرين المستندين إلى واجهة برمجة التطبيقات والمستمعين المستندين إلى البيان.
من الأنماط الشائعة تسجيل مستمع بمسار أو بادئة مسار معيّنة
باستخدام collectAsStateWithLifecycle(). من خلال تنفيذ المستمعين بهذه الطريقة، يمكن لتطبيقك تلقّي الأحداث بشكل أكثر انتقائية، ما يحسّن تصميمه وكفاءته.