عند إجراء طلب إلى Data Layer API، يمكنك تلقّي حالة الطلب عند اكتماله. يمكنك أيضًا الاستماع إلى أحداث البيانات الناتجة عن تغييرات البيانات التي يجريها تطبيقك في أي مكان على شبكة Wear OS by Google.
للاطّلاع على مثال حول كيفية استخدام Data Layer API بفعالية، راجِع تطبيق نموذج DataLayer لنظام Android.
انتظِر حالة طلبات طبقة البيانات
تُرجع الطلبات التي يتم إرسالها إلى 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 } }
رصد أحداث طبقة البيانات
بما أنّ طبقة البيانات تعمل على مزامنة البيانات وإرسالها بين الأجهزة المحمولة وأجهزة الارتداء، عليك عادةً الاستماع إلى الأحداث المهمة، مثل إنشاء عناصر البيانات وتلقّي الرسائل.
لرصد أحداث طبقة البيانات، لديك خياران:
- أنشئ خدمة توسّع
WearableListenerService. - أنشئ نشاطًا أو صفًا يطبّق واجهة
DataClient.OnDataChangedListener.
باستخدام أيّ من هذين الخيارَين، يمكنك تجاهل طرق معاودة الاتصال الخاصة بأحداث البيانات للأحداث التي يهمّك التعامل معها.
ملاحظة: يجب مراعاة استهلاك تطبيقك للبطارية عند اختيار طريقة تنفيذ أداة معالجة الأحداث. يتم تسجيل WearableListenerService في بيان التطبيق ويمكنه تشغيل التطبيق إذا لم يكن قيد التشغيل. إذا كنت بحاجة فقط إلى الاستماع إلى الأحداث عندما يكون تطبيقك قيد التشغيل، وهو ما يحدث غالبًا مع التطبيقات التفاعلية، فلا تستخدم WearableListenerService. بدلاً من ذلك، سجِّل مستمعًا مباشرًا. على سبيل المثال، استخدِم طريقة addListener للفئة DataClient. ويمكن أن يؤدي ذلك إلى تقليل الحِمل على النظام وتقليل استهلاك البطارية.
استخدام WearableListenerService
يمكنك عادةً إنشاء مثيلات من WearableListenerService في كل من تطبيقات الأجهزة القابلة للارتداء وتطبيقات الأجهزة الجوّالة. ومع ذلك، إذا لم تكن مهتمًا بأحداث البيانات في أحد التطبيقات، لن تحتاج إلى تنفيذ الخدمة في هذا التطبيق.
على سبيل المثال، يمكنك إنشاء تطبيق على جهاز محمول يضبط ويحصل على عناصر بيانات، وتطبيق على جهاز قابل للارتداء يستمع إلى هذه التعديلات لتعديل واجهة المستخدم. لا يحدّث تطبيق الجهاز القابل للارتداء أيًا من عناصر البيانات، لذا لا يستمع تطبيق الجهاز المحمول إلى أي أحداث بيانات من تطبيق الجهاز القابل للارتداء.
في ما يلي بعض الأحداث التي يمكنك الاستماع إليها باستخدام WearableListenerService:
onDataChanged(): عندما يتم إنشاء عنصر بيانات أو حذفه أو تغييره، يشغّل النظام عملية رد الاتصال هذه على جميع العُقد المتصلة.-
onMessageReceived(): يتم تشغيل عملية الاسترجاع هذه على العقدة المستهدَفة عند إرسال رسالة من عقدة. onCapabilityChanged(): عندما تصبح إحدى الميزات التي يعلن عنها مثيل تطبيقك متاحة على الشبكة، يؤدي هذا الحدث إلى تشغيل هذا الرمز البرمجي. إذا كنت تبحث عن عقدة مجاورة، يمكنك طلب البحث باستخدام طريقةisNearby()للعُقد المقدَّمة في رد الاتصال.
يمكنك أيضًا الاستماع إلى الأحداث من ChannelClient.ChannelCallback، مثل onChannelOpened().
يتم تنفيذ جميع الأحداث السابقة في سلسلة محادثات في الخلفية، وليس في سلسلة المحادثات الرئيسية.
لإنشاء WearableListenerService، اتّبِع الخطوات التالية:
- أنشئ فئة تتضمّن
WearableListenerService. - استمع إلى الأحداث التي تهمّك، مثل
onDataChanged(). - عليك تعريف فلتر أهداف في ملف البيان لنظام التشغيل 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 العادية. يمكنك تحديد خدمات متعددة لكل بيان، وفلاتر أهداف متعددة لكل خدمة، وإجراءات متعددة لكل فلتر، ومقاطع بيانات متعددة لكل فلتر. يمكن أن تتطابق الفلاتر مع مضيف بدل أو مضيف محدّد. للحصول على تطابق مع مضيف يستخدم حرف بدل، استخدِم host="*". للمطابقة مع مضيف معيّن، حدِّد host=<node_id>.
يمكنك أيضًا مطابقة مسار حرفي أو بادئة مسار. لإجراء ذلك، يجب تحديد حرف بدل أو مضيف معيّن. وفي ما عدا ذلك، يتجاهل النظام المسار الذي تحدّده.
لمزيد من المعلومات حول أنواع الفلاتر التي يتيحها Wear OS، يُرجى الاطّلاع على مستندات مرجع واجهة برمجة التطبيقات الخاصة بـ WearableListenerService.
لمزيد من المعلومات عن فلاتر البيانات وقواعد المطابقة، يُرجى الاطّلاع على مستندات مرجع واجهة برمجة التطبيقات الخاصة بعنصر البيان <data>.
عند مطابقة فلاتر الأهداف، تذكَّر قاعدتَين مهمتَين:
- إذا لم يتم تحديد أي مخطط لفلتر الأهداف، سيتجاهل النظام جميع سمات معرّف الموارد المنتظم (URI) الأخرى.
- في حال عدم تحديد مضيف للفلتر، يتجاهل النظام جميع سمات المسار.
استخدام مستمع مباشر
إذا كان تطبيقك يهتم فقط بأحداث طبقة البيانات عندما يتفاعل المستخدم مع التطبيق، قد لا يحتاج إلى خدمة طويلة الأمد للتعامل مع كل تغيير في البيانات. في هذه الحالة، يمكنك الاستماع إلى الأحداث في نشاط.
لتقديم طريقة أنظف وأكثر أمانًا، استخدِم Lifecycle Observer. باستخدام Lifecycle Observer، يمكنك نقل منطق التسجيل من onResume() في Activity إلى فئة منفصلة قابلة لإعادة الاستخدام تنفّذ DefaultLifecycleObserver.
يساعد هذا الأسلوب في الحفاظ على نشاطك بسيطًا ويمنع حدوث أخطاء شائعة، مثل نسيان إلغاء تسجيل أداة معالجة الحدث.
1. إنشاء أداة معالجة تتوافق مع مراحل النشاط
يغلّف هذا الصف DataClient.OnDataChangedListener ويدير تلقائيًا
اشتراكه الخاص استنادًا إلى مراحل نشاط Activity.
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- الاستخدام في "نشاطك"
الآن، لا يحتاج نشاطك إلى إلغاء onResume() أو onPause() لواجهة برمجة التطبيقات Wear API. تضيف المراقب مرة واحدة في 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 ... } }
مزايا هذه الطريقة:
- Cleaner Activity: يمكنك إزالة الرمز المتكرّر من طرق دورة حياة النشاط.
- الأمان: تساعد
DefaultLifecycleObserverفي التأكّد من إزالة المستمع حتى إذا تم إيقاف النشاط بشكل غير متوقّع، ما يمنع تسرُّب الذاكرة. - إمكانية إعادة الاستخدام: يمكنك توصيل
WearDataLayerObserverبأي Activity أو Fragment بدون إعادة كتابة منطق التسجيل. - الفصل: يتم فصل منطق تحديد وقت الاستماع عن منطق تحديد كيفية التعامل مع البيانات.
استخدام الفلاتر مع المستمعين المباشرين
كما ذكرنا سابقًا، يمكنك تحديد فلاتر الأهداف لعناصر WearableListenerService المستندة إلى ملف البيان، ويمكنك أيضًا استخدام فلاتر الأهداف عند تسجيل أداة معالجة مباشرة من خلال Wearable API. تنطبق القواعد نفسها على كلّ من أدوات الاستماع المباشر المستندة إلى واجهة برمجة التطبيقات وأدوات الاستماع المستندة إلى ملف البيان.
يتمثل أحد الأنماط الشائعة في تسجيل معالج باستخدام مسار أو بادئة مسار معيّنَين
باستخدام LifecycleObserver. ومن خلال تنفيذ أدوات معالجة الأحداث بهذه الطريقة، يمكن لتطبيقك تلقّي الأحداث بشكل أكثر انتقائية، ما يحسّن تصميمه وكفاءته.