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

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

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

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

تُرجع طلبات البيانات من واجهة برمجة التطبيقات الخاصة بطبقة البيانات، مثل طلب باستخدام طريقة 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) {
  ...
}

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

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

لرصد أحداث طبقة البيانات، لديك خياران:

باستخدام أيّ من هذين الخيارَين، يمكنك تجاهل طرق معاودة الاتصال ببيانات الأحداث للأحداث التي يهمّك التعامل معها.

ملاحظة: يجب مراعاة استهلاك تطبيقك للبطارية عند اختيار طريقة تنفيذ أداة معالجة الأحداث. يتم تسجيل 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>.

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

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

استخدام ميزة "الاستماع المباشر"

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

لإنشاء نشاط يستمع إلى أحداث البيانات، اتّبِع الخطوات التالية:

  1. نفِّذ الواجهات المطلوبة.
  2. في الطريقتَين onCreate() أو onResume()، استخدِم Wearable.getDataClient(this).addListener() أو MessageClient.addListener() أو CapabilityClient.addListener() أو ChannelClient.registerChannelCallback() لإعلام &quot;خدمات Google Play&quot; بأنّ نشاطك مهتم بتلقّي إشعارات بشأن أحداث طبقة البيانات.
  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());
            }
        }
    }
}

تنبيه: قبل استخدام Wearable Data Layer API، تأكَّد من توفّرها على جهاز، وإلا سيحدث استثناء. استخدِم فئة GoogleApiAvailability، كما هو موضّح في Horologist.

استخدام الفلاتر مع المستمعين المباشرين

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

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