Wear पर डेटा लेयर इवेंट मैनेज करना

Data Layer API को कॉल करने पर, कॉल पूरा होने के बाद आपको कॉल का स्टेटस मिल सकता है. इसके अलावा, Wear OS by Google नेटवर्क पर कहीं भी आपके ऐप्लिकेशन के डेटा में हुए बदलावों से जनरेट होने वाले डेटा इवेंट भी सुने जा सकते हैं.

डेटा लेयर एपीआई का असरदार तरीके से इस्तेमाल करने का उदाहरण देखने के लिए, Android DataLayer Sample ऐप्लिकेशन देखें.

डेटा लेयर कॉल के स्टेटस का इंतज़ार करना

डेटा लेयर एपीआई को किए गए कॉल, जैसे कि putDataItem क्लास के DataClient तरीके का इस्तेमाल करके किया गया कॉल, कभी-कभी Task<ResultType> ऑब्जेक्ट दिखाता है. Task ऑब्जेक्ट के बनने के तुरंत बाद, ऑपरेशन को बैकग्राउंड में कतार में लगा दिया जाता है. इसके बाद, कोई और कार्रवाई न करने पर, यह प्रोसेस अपने-आप पूरी हो जाएगी.

हालांकि, आम तौर पर ऑपरेशन पूरा होने के बाद, आपको नतीजे के साथ कुछ करना होता है. इसलिए, Task ऑब्जेक्ट की मदद से, नतीजे की स्थिति का इंतज़ार किया जा सकता है. यह इंतज़ार एसिंक्रोनस या सिंक्रोनस तरीके से किया जा सकता है.

एसिंक्रोनस कॉल

अगर आपका कोड मुख्य यूज़र इंटरफ़ेस (यूआई) थ्रेड पर चल रहा है, तो डेटा लेयर एपीआई को ब्लॉक करने वाले कॉल न करें. 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 में, तो कॉल को ब्लॉक करना ठीक है. इस मामले में, Task ऑब्जेक्ट पर Tasks.await() को कॉल किया जा सकता है. यह अनुरोध पूरा होने तक ब्लॉक रहता है और 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 का इस्तेमाल न करें. ऐसा अक्सर इंटरैक्टिव ऐप्लिकेशन के साथ होता है. इसके बजाय, लाइव लिसनर रजिस्टर करें. उदाहरण के लिए, DataClient क्लास के addListener तरीके का इस्तेमाल करें. इससे सिस्टम पर लोड कम हो सकता है और बैटरी की खपत भी कम हो सकती है.

WearableListenerService का इस्तेमाल करना

आम तौर पर, WearableListenerService के इंस्टेंस, Wearable और हैंडहेल्ड ऐप्लिकेशन, दोनों में बनाए जाते हैं. हालांकि, अगर आपको किसी ऐप्लिकेशन में डेटा इवेंट ट्रैक नहीं करने हैं, तो आपको उस ऐप्लिकेशन में सेवा लागू करने की ज़रूरत नहीं है.

उदाहरण के लिए, आपके पास एक हैंडहेल्ड ऐप्लिकेशन हो सकता है, जो डेटा आइटम ऑब्जेक्ट सेट करता है और उन्हें वापस पाता है. साथ ही, आपके पास एक वियरेबल ऐप्लिकेशन हो सकता है, जो इन अपडेट को सुनकर अपने यूज़र इंटरफ़ेस (यूआई) को अपडेट करता है. वियरेबल डिवाइस पर मौजूद ऐप्लिकेशन, किसी भी डेटा आइटम को कभी अपडेट नहीं करता. इसलिए, हैंडहेल्ड डिवाइस पर मौजूद ऐप्लिकेशन, वियरेबल डिवाइस पर मौजूद ऐप्लिकेशन से किसी भी डेटा इवेंट को नहीं सुनता.

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() तरीके में, Google Play services को यह सूचना देने के लिए कि आपकी गतिविधि को डेटा लेयर इवेंट सुनने में दिलचस्पी है, Wearable.getDataClient(this).addListener(), MessageClient.addListener(), CapabilityClient.addListener() या ChannelClient.registerChannelCallback() को कॉल करें.
  3. onStop() या onPause() में, DataClient.removeListener(), MessageClient.removeListener(), CapabilityClient.removeListener() या ChannelClient.unregisterChannelCallback() का इस्तेमाल करके रजिस्टर किए गए सभी लिसनर को अनरजिस्टर करें.
  4. अगर किसी गतिविधि को सिर्फ़ किसी खास पाथ प्रीफ़िक्स वाले इवेंट में दिलचस्पी है, तो उपयुक्त प्रीफ़िक्स फ़िल्टर वाला लिसनर जोड़ा जा सकता है. इससे सिर्फ़ वह डेटा मिलेगा जो ऐप्लिकेशन की मौजूदा स्थिति के हिसाब से काम का है.
  5. आपने जिन इंटरफ़ेस को लागू किया है उनके आधार पर, onDataChanged(), onMessageReceived(), onCapabilityChanged() या ChannelClient.ChannelCallback के तरीकों को लागू करें. इन तरीकों को मुख्य थ्रेड पर कॉल किया जाता है. इसके अलावा, WearableOptions का इस्तेमाल करके, कस्टम Looper तय किया जा सकता है.

यहां 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() तरीके में लिसनर को हटाया जाता है. इस तरह से लिसनर लागू करने पर, आपका ऐप्लिकेशन ज़्यादा चुनिंदा तरीके से इवेंट पा सकता है. इससे ऐप्लिकेशन के डिज़ाइन और परफ़ॉर्मेंस को बेहतर बनाने में मदद मिलती है.