التعامل مع أحداث طبقة البيانات على Wear

عند إجراء طلب بواجهة Data Layer API، يمكنك تلقّي حالة الطلب عند اكتماله. يمكنك أيضًا الاطّلاع على أحداث البيانات الناتجة عن التغييرات التي يجريها تطبيقك في أي مكان على شبكة "Wear OS من Google".

للاطّلاع على مثال على استخدام واجهة برمجة التطبيقات Data Layer API بفعالية، يمكنك مراجعة تطبيق نموذج Android DataLayer.

انتظار حالة طلبات طبقة البيانات

تؤدي الاستدعاءات إلى واجهة برمجة التطبيقات لطبقة البيانات، مثل استدعاء باستخدام الطريقة putDataItem من الفئة DataClient، في بعض الأحيان إلى عرض كائن Task<ResultType>. فور إنشاء كائن Task، يتم وضع العملية في "قائمة المحتوى التالي" في الخلفية. إذا لم تفعل أي شيء آخر بعد ذلك، فستنتهي العملية في نهاية المطاف في صمت.

في المقابل، عادةً ما تحتاج إلى تنفيذ إجراء على النتيجة بعد اكتمال العملية، لذلك يتيح لك الكائن Task انتظار حالة النتيجة، سواء بشكل غير متزامن أو متزامنًا.

الاتصالات غير المتزامنة

إذا كان الرمز الخاص بك يعمل في سلسلة محادثات واجهة المستخدم الرئيسية، لا تُجرِ استدعاءات لحظر واجهة برمجة التطبيقات Data Layer API. يمكنك إجراء الطلبات بشكل غير متزامن من خلال إضافة طريقة استدعاء إلى عنصر Task الذي يتم تنشيطه عند اكتمال العملية:

Kotlin

// 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>) { ... }

Java

// Using Java 8 Lambdas.
task.addOnSuccessListener(dataItem -> handleDataItem(dataItem));
task.addOnFailureListener(exception -> handleDataItemError(exception));
task.addOnCompleteListener(task -> handleTaskComplete(task));

ويمكنك الانتقال إلى Task API للاطّلاع على الاحتمالات الأخرى، بما في ذلك تنفيذ المهام المختلفة بشكل تسلسلي.

المكالمات المتزامنة

إذا كان الرمز الخاص بك يعمل في سلسلة محادثات معالِج منفصلة ضمن خدمة تعمل في الخلفية، كما هو الحال في WearableListenerService، لا بأس في حظر المكالمات. في هذه الحالة، يمكنك استدعاء Tasks.await() على الكائن Task، الذي يتم حظره حتى اكتمال الطلب وعرض الكائن Result. ويظهر ذلك في المثال التالي.

ملاحظة: احرِص على عدم استدعاء هذا الحدث في سلسلة التعليمات الرئيسية.

Kotlin

try {
    Tasks.await(dataItemTask).apply {
        Log.d(TAG, "Data item set: $uri")
    }
}
catch (e: ExecutionException) { ... }
catch (e: InterruptedException) { ... }

Java

try {
    DataItem item = Tasks.await(dataItemTask);
    Log.d(TAG, "Data item set: " + item.getUri());
} catch (ExecutionException | InterruptedException e) {
  ...
}

الاستماع إلى أحداث طبقة البيانات

نظرًا لأن طبقة البيانات تعمل على مزامنة البيانات وإرسالها عبر الأجهزة المحمولة باليد والقابلة للارتداء، عادةً ما تحتاج إلى الاستماع إلى الأحداث المهمة مثل عناصر البيانات التي يتم إنشاؤها والرسائل التي يتم استلامها.

للاستماع إلى أحداث طبقة البيانات، لديك خياران:

باستخدام هذين الخيارَين، يمكنك إلغاء طرق استدعاء أحداث البيانات للأحداث التي تريد معالجتها.

ملاحظة: يجب مراعاة استخدام تطبيقك للبطارية عند اختيار تنفيذ المستمعين. تم تسجيل WearableListenerService في ملف البيان الخاص بالتطبيق ويمكنه تشغيل التطبيق إذا لم يكن قيد التشغيل. إذا كنت تحتاج إلى الاستماع إلى الأحداث فقط عندما يكون تطبيقك قيد التشغيل، وهو ما يحدث غالبًا في التطبيقات التفاعلية، لا تستخدم WearableListenerService. بدلاً من ذلك، يمكنك تسجيل مستمع مباشر. على سبيل المثال، يمكنك استخدام طريقة addListener للفئة DataClient. يمكن أن يؤدي ذلك إلى تقليل الحمل على النظام وتقليل استخدام البطارية.

استخدام WearableListenerService

يمكنك عادةً إنشاء نُسخ WearableListenerService في كل من التطبيقات القابلة للارتداء والتطبيقات المحمولة باليد. أمّا إذا لم تكن مهتمًا بأحداث البيانات في أحد التطبيقات، فلن تحتاج إلى تنفيذ الخدمة في ذلك التطبيق.

على سبيل المثال، يمكن أن يكون لديك تطبيق محمول يضبط كائنات عناصر البيانات ويحصل عليها وتطبيق قابل للارتداء ينتظر هذه التحديثات لتحديث واجهة المستخدم الخاصة به. لا يحدّث تطبيق الأجهزة القابلة للارتداء أيًا من عناصر البيانات، لذلك لا يستمع التطبيق المحمول باليد إلى أي أحداث بيانات من التطبيق القابل للارتداء.

وفي ما يلي بعض الأحداث التي يمكنك الاستماع إليها باستخدام WearableListenerService:

  • onDataChanged(): عند إنشاء عنصر بيانات أو حذفه أو تغييره، يشغِّل النظام رد الاستدعاء هذا على جميع العُقد المرتبطة.
  • onMessageReceived(): تؤدي رسالة مُرسَلة من عقدة إلى تشغيل معاودة الاتصال هذه على العقدة الهدف.
  • onCapabilityChanged(): عندما تصبح إحدى الإمكانيات التي يعلن عنها تطبيقك متاحة على الشبكة، يؤدي هذا الحدث إلى تشغيل معاودة الاتصال هذه. إذا كنت تبحث عن عقدة قريبة، يمكنك طلب البحث عن طريقة isNearby() الخاصة بالعُقد المتوفرة في رد الاتصال.

ويمكنك أيضًا الاستماع إلى أحداث من ChannelClient.ChannelCallback، مثل onChannelOpened().

يتم تنفيذ جميع الأحداث السابقة في سلسلة محادثات في الخلفية، وليس على سلسلة التعليمات الرئيسية.

لإنشاء WearableListenerService، يُرجى اتّباع الخطوات التالية:

  1. أنشئ صفًا يتضمّن امتداد WearableListenerService.
  2. يمكنك الاستماع إلى الأحداث التي تهتم بها، مثل onDataChanged().
  3. حدِّد أحد فلاتر الأهداف في ملف بيان Android لإشعار النظام بشأن WearableListenerService. يتيح هذا البيان للنظام ربط خدمتك حسب الحاجة.

يوضّح المثال التالي كيفية تنفيذ سمة WearableListenerService بسيطة:

Kotlin

private const val TAG = "DataLayerSample"
private const val START_ACTIVITY_PATH = "/start-activity"
private const val DATA_ITEM_RECEIVED_PATH = "/data-item-received"

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)
                }
    }
}

Java

public class DataLayerListenerService extends WearableListenerService {
    private static final String TAG = "DataLayerSample";
    private static final String START_ACTIVITY_PATH = "/start-activity";
    private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        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.
        for (DataEvent event : dataEvents) {
            Uri uri = event.getDataItem().getUri();

            // Get the node ID from the host value of the URI.
            String nodeId = uri.getHost();
            // Set the data of the message to be the bytes of the URI.
            byte[] payload = uri.toString().getBytes();

            // Send the RPC.
            Wearable.getMessageClient(this).sendMessage(
                  nodeId,  DATA_ITEM_RECEIVED_PATH, payload);
        }
    }
}

يوضّح القسم التالي كيفية استخدام فلتر أهداف مع أداة الاستماع هذه.

استخدام الفلاتر مع WearableListenerService

قد يبدو فلتر الأهداف للمثال WearableListenerService المعروض في القسم السابق على النحو التالي:

<service android:name=".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 محلّ إجراء BIND_LISTENER المقترَح سابقًا لكي يتم تشغيل تطبيقك أو أحداث معيّنة فقط. ويساهم هذا التغيير في تحسين كفاءة النظام وتقليل استهلاك البطارية وغيرها من الأعباء المتزايدة المرتبطة بتطبيقك. في هذا المثال، ستستمع الساعة إلى عنصر بيانات /start-activity ويستمع الهاتف إلى استجابة رسالة /data-item-received.

تنطبق قواعد مطابقة فلتر Android العادي. يمكنك تحديد خدمات متعددة لكل بيان وفلاتر أهداف متعددة لكل خدمة وإجراءات متعددة لكل فلتر والعديد من مقاطع البيانات لكل فلتر. يمكن أن تتطابق عوامل التصفية على مضيف حرف بدل أو على مضيف معين. للمطابقة على مضيف حرف بدل، استخدِم host="*". للمطابقة على مضيف معيّن، حدِّد host=<node_id>.

يمكنك أيضًا مطابقة مسار حرفي أو بادئة مسار حرفية. لتنفيذ ذلك، يتعين عليك تحديد حرف بدل أو مضيف محدد. وبخلاف ذلك، يتجاهل النظام المسار الذي تحدده.

لمزيد من المعلومات حول أنواع الفلاتر المتوافقة مع نظام التشغيل Wear OS، يمكنك الاطّلاع على المستندات المرجعية لواجهة برمجة التطبيقات WearableListenerService.

للمزيد من المعلومات حول فلاتر البيانات وقواعد المطابقة، يمكنك الاطّلاع على المستندات المرجعية لواجهة برمجة التطبيقات الخاصة بعنصر بيان <data>.

عند مطابقة فلاتر الأهداف، ضَع في اعتبارك قاعدتَين مهمتَين:

  • في حال عدم تحديد مخطط لفلتر الأهداف، يتجاهل النظام جميع سمات معرّف الموارد المنتظم (URI) الأخرى.
  • إذا لم يتم تحديد أي مضيف للفلتر، يتجاهل النظام جميع سمات المسار.

استخدام مستمِع مباشر

إذا كان تطبيقك لا يهتم إلا بأحداث طبقة البيانات عند تفاعل المستخدم مع التطبيق، قد لا يحتاج إلى خدمة طويلة الأمد للتعامل مع كل تغيير في البيانات. وفي هذه الحالة، يمكنك متابعة الأحداث في أحد الأنشطة من خلال تنفيذ واجهة أو أكثر من الواجهات التالية:

لإنشاء نشاط يرصد أحداث البيانات، قم بما يلي:

  1. نفِّذ الواجهات المطلوبة.
  2. في طريقة onCreate() أو onResume()، اتّصِل بـ Wearable.getDataClient(this).addListener() أو MessageClient.addListener() أو CapabilityClient.addListener() أو ChannelClient.registerChannelCallback() لإعلام خدمات Google Play بأنّ نشاطك مهتم بالاستماع إلى أحداث طبقة البيانات.
  3. في onStop() أو onPause()، يُرجى إلغاء تسجيل أي مستمعين باستخدام DataClient.removeListener() أو MessageClient.removeListener() أو CapabilityClient.removeListener() أو ChannelClient.unregisterChannelCallback().
  4. إذا كان أحد الأنشطة مهتمًا فقط بالأحداث ذات بادئة مسار معيّنة، يمكنك إضافة أداة معالجة باستخدام فلتر بادئة مناسب لتلقّي البيانات ذات الصلة بحالة التطبيق الحالية فقط.
  5. نفِّذ onDataChanged() أو onMessageReceived() أو onCapabilityChanged() أو طرق من ChannelClient.ChannelCallback، بناءً على الواجهات التي نفّذتها. يتم استدعاء هذه الطرق في سلسلة التعليمات الرئيسية، أو يمكنك تحديد Looper مخصّص باستخدام WearableOptions.

في ما يلي مثال يستخدم DataClient.OnDataChangedListener:

Kotlin

class MainActivity : Activity(), DataClient.OnDataChangedListener {

    public override fun onResume() {
        Wearable.getDataClient(this).addListener(this)
    }

    override fun 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)
            }
        }
    }
}

Java

public class MainActivity extends Activity implements DataClient.OnDataChangedListener {

    @Override
    public void onResume() {
        Wearable.getDataClient(this).addListener(this);
    }

    @Override
    protected void onPause() {
        Wearable.getDataClient(this).removeListener(this);
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        for (DataEvent event : dataEvents) {
            if (event.getType() == DataEvent.TYPE_DELETED) {
                Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
            } else if (event.getType() == DataEvent.TYPE_CHANGED) {
                Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri());
            }
        }
    }
}

استخدام الفلاتر مع أدوات الاستماع المباشرة

كما ذكرنا سابقًا، يمكنك استخدام فلاتر الأهداف عند تسجيل مستمع مباشر من خلال واجهة برمجة التطبيقات القابلة للارتداء، تمامًا كما يمكنك تحديد فلاتر الأهداف لكائنات WearableListenerService المستندة إلى البيانات. وتنطبق القواعد نفسها على كل من أدوات معالجة البيانات المباشرة المستندة إلى واجهة برمجة التطبيقات والمستمعين المستنِدين إلى البيانات.

وأحد الأنماط الشائعة هو تسجيل المستمع بمسار أو بادئة مسار محدّدتَين بطريقة onResume() في أحد الأنشطة، ثم إزالة المستمع من خلال طريقة onPause() الخاصة بالنشاط. يتيح تنفيذ أدوات معالجة الحدث بهذه الطريقة لتطبيقك استقبال الأحداث بشكل أكثر انتقائية، لتحسين تصميمه وكفاءته.