1page.title=Handling Data Layer Events
2
3@jd:body
4
5<div id="tb-wrapper">
6<div id="tb">
7
8<h2>This lesson teaches you to</h2>
9<ol>
10  <li><a href="#Wait">Wait for the Status of Data Layer Calls</a></li>
11  <li><a href="#Listen">Listen for Data Layer Events</a></li>
12</ol>
13
14</div>
15</div>
16
17<p>When you make calls to the Data Layer API, you can receive the status
18of the call when it completes as well as listen for any changes that
19the call ends up making with listeners.
20</p>
21
22<h2 id="Wait">Wait for the Status of Data Layer Calls</h2>
23
24<p>You'll notice that calls to the Data Layer API sometimes return a
25<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>,
26such as
27<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>putDataItem()</code></a>.
28As soon as the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> is created,
29the operation is queued in the background. If you do nothing else after this, the operation
30eventually completes silently. However, you'll usually want to do something with the result
31after the operation completes, so the
32<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
33lets you wait for the result status, either synchronously or asynchronously.
34</p>
35
36<h3 id="async-waiting">Asynchronous calls</h3>
37<p>If your code is running on the main UI thread, do not make blocking calls
38to the Data Layer API. You can run the calls asynchronously by adding a callback method
39to the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> object,
40which fires when the operation is completed:</p>
41<pre>
42pendingResult.setResultCallback(new ResultCallback&lt;DataItemResult&gt;() {
43    &#64;Override
44    public void onResult(final DataItemResult result) {
45        if(result.getStatus().isSuccess()) {
46            Log.d(TAG, "Data item set: " + result.getDataItem().getUri());
47        }
48    }
49});
50</pre>
51
52<h3 id="sync-waiting">Synchronous calls</h3>
53<p>If your code is running on a separate handler thread in a background service (which is the case
54in a <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>),
55it's fine for the calls to block. In this case, you can call
56<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html#await()"><code>await()</code></a>
57on the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
58object, which blocks until the request completes and returns a
59<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/Result.html"><code>Result</code></a>
60object:
61</p>
62
63<pre>
64DataItemResult result = pendingResult.await();
65if(result.getStatus().isSuccess()) {
66    Log.d(TAG, "Data item set: " + result.getDataItem().getUri());
67}
68</pre>
69
70
71<h2 id="Listen">Listen for Data Layer Events</h2>
72<p>
73Because the data layer synchronizes and sends data across the handheld and
74wearable, it is usually necessary to listen for important events. Examples of
75such events include creation of data items and receipt of messages.
76</p>
77<p>
78To listen for data layer events, you have two options:
79</p>
80<ul>
81   <li>Create a service that extends <a href
82="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html">
83{@code WearableListenerService}</a>.</li>
84   <li>Create an activity that implements <a
85href="https://developer.android.com/reference/com/google/android/gms/wearable/DataApi.DataListener.html">
86{@code DataApi.DataListener}</a>.</li>
87</ul>
88<p>
89With both these options, you override the data event callback methods for the
90events you are interested in handling.
91</p>
92<h3>With a WearableListenerService</h3>
93<p>
94You typically create instances of this service in both your wearable and
95handheld apps. If you are not interested in data events in one of these apps,
96then you don't need to implement this service in that particular app.
97</p>
98<p>
99For example, you can have a handheld app that sets and gets data item objects
100and a wearable app that listens for these updates to update its UI. The
101wearable never updates any of the data items, so the handheld app doesn't
102listen for any data events from the wearable app.
103</p>
104<p>
105Some of the events you can listen for using <a
106href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
107{@code WearableListenerService}</a> are as follows:
108</p>
109<ul>
110  <li><a
111href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
112{@code onDataChanged()}</a>:
113Whenever a data item object is created, deleted, or changed, the system triggers
114this callback on all connected nodes.
115</li>
116<li><a
117href="http://developer.android.com/reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)">
118{@code onMessageReceived()}</a>:  A message sent from a node triggers
119this callback on the target node.</li>
120<li><a
121href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html#onCapabilityChanged(com.google.android.gms.wearable.CapabilityInfo)">
122{@code onCapabilityChanged()}</a>:
123When a capability that an instance of your app advertises becomes available
124on the network, that event triggers this callback. If you're looking for a
125nearby node you can query the
126<a
127href="https://developers.google.com/android/reference/com/google/android/gms/wearable/Node.html#isNearby()">
128{@code isNearby()}</a> method of the nodes provided in the callback.</li>
129
130<p>
131In addition to those on this list, you can listen for events from
132<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener">
133{@code ChannelApi.ChannelListener}</a>, such as
134<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html#onChannelOpened(com.google.android.gms.wearable.Channel)">
135{@code onChannelOpened()}</a>.
136</p>
137</ul>
138<p>To create a <a
139href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>, follow these steps:</p>
140
141<ol>
142  <li>Create a class that extends
143  <a
144href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>.
145  </li>
146  <li>Listen for the events that you're interested in, such as
147  <a
148href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
149<code>onDataChanged()</code></a>.
150  </li>
151  <li>Declare an intent filter in your Android manifest to notify the system
152about your
153  <a
154href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>
155WearableListenerService</code></a>.
156  This declaration allows the system to bind your service as needed.
157  </li>
158</ol>
159
160  <p>The following example shows how to implement a simple
161  <a
162href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>
163WearableListenerService</code></a>:
164  </p>
165<pre>
166public class DataLayerListenerService extends WearableListenerService {
167
168    private static final String TAG = "DataLayerSample";
169    private static final String START_ACTIVITY_PATH = "/start-activity";
170    private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";
171
172    &#64;Override
173    public void onDataChanged(DataEventBuffer dataEvents) {
174        if (Log.isLoggable(TAG, Log.DEBUG)) {
175            Log.d(TAG, "onDataChanged: " + dataEvents);
176        }
177        final List events = FreezableUtils
178                .freezeIterable(dataEvents);
179
180        GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
181                .addApi(Wearable.API)
182                .build();
183
184        ConnectionResult connectionResult =
185                googleApiClient.blockingConnect(30, TimeUnit.SECONDS);
186
187        if (!connectionResult.isSuccess()) {
188            Log.e(TAG, "Failed to connect to GoogleApiClient.");
189            return;
190        }
191
192        // Loop through the events and send a message
193        // to the node that created the data item.
194        for (DataEvent event : events) {
195            Uri uri = event.getDataItem().getUri();
196
197            // Get the node id from the host value of the URI
198            String nodeId = uri.getHost();
199            // Set the data of the message to be the bytes of the URI
200            byte[] payload = uri.toString().getBytes();
201
202            // Send the RPC
203            Wearable.MessageApi.sendMessage(googleApiClient, nodeId,
204                    DATA_ITEM_RECEIVED_PATH, payload);
205        }
206    }
207}
208</pre>
209
210<p>
211The next section explains how to use an intent filter with this listener.
212</p>
213
214<h3>Using filters with WearableListenerService</h3>
215
216<p>
217An intent filter for the
218<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html">
219{@code WearableListenerService}</a> example shown in the previous section might look like this:
220
221<pre>
222&lt;service android:name=".DataLayerListenerService"&gt;
223  &lt;intent-filter>
224      &lt;action android:name="com.google.android.gms.wearable.DATA_CHANGED" /&gt;
225      &lt;data android:scheme="wear" android:host="*"
226               android:path="/start-activity" /&gt;
227  &lt;/intent-filter&gt;
228&lt;/service&gt;
229</pre>
230
231<p>
232In this filter, the {@code DATA_CHANGED} action replaces the
233previously recommended {@code BIND_LISTENER} action so that only specific
234events wake or launch your application. This change improves system efficiency
235and reduces battery consumption and other overhead associated with your
236application. In this example, the watch listens for the
237{@code /start-activity} data item, and the
238phone listens for the {@code /data-item-received} message response.
239</p>
240<p>
241Standard Android filter matching rules apply. You can specify multiple services
242per manifest, multiple intent filters per service, multiple actions per filter,
243and multiple data stanzas per filter. Filters can match on a wildcard host or on
244a specific one. To match on a wildcard host, use {@code host="*"}. To match
245on a specific host, specify {@code host=&lt;node_id&gt;}.
246</p>
247
248<p>
249You can also match a literal path or path prefix. If you are matching by path
250or path prefix, you must specify a wildcard or specific host.
251If you do not do so, the system ignores the path you specified.
252</p>
253
254<p>
255For more information on the filter types that Wear supports, see the
256API reference documentation for <a
257href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService">
258{@code WearableListenerService}</a>.
259</p>
260
261<p>
262For more information on data filters and matching rules, see the API reference
263documentation for the <a
264href="{@docRoot}guide/topics/manifest/data-element.html">{@code data}</a>
265manifest element.
266</p>
267
268<p>When matching intent filters, there are two important rules to remember:</p>
269<ul>
270    <li>If a scheme is not specified for the intent filter, the system ignores
271    all the other URI attributes.</li>
272    <li>If no host is specified for the filter, the system ignores the
273    port attribute and all the path attributes.</li>
274</ul>
275
276<h3>With a listener activity</h3>
277<p>
278If your app only cares about data-layer events when the user is interacting
279with the app, it may not need a long-running service to handle every data
280change. In such a case, you can listen for events in an activity by
281implementing one or more of the following interfaces:
282</p>
283<ul>
284  <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>
285  DataApi.DataListener</code></a></li>
286
287  <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.MessageListener.html">
288  <code>MessageApi.MessageListener</code></a></li>
289
290  <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener.html">{@code CapabilityApi.CapabilityListener}</a></li>
291</ul>
292
293<p>To create an activity that listens for data events:</p>
294<ol>
295<li>Implement the desired interfaces.</li>
296<li>In {@link android.app.Activity#onCreate onCreate()}, create an instance of
297<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code>
298</a>to work with the Data Layer API.</li>
299
300<li>
301In {@link android.app.Activity#onStart onStart()}, call <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">
302<code>connect()</code></a> to connect the client to Google Play services.
303</li>
304
305<li>When the connection to Google Play services is established, the system calls
306<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>. This is where you call
307
308<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)">
309<code>DataApi.addListener()</code></a>,
310
311<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener, android.net.Uri, int)">
312<code>MessageApi.addListener()</code></a>, or
313
314<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient,%20com.google.android.gms.wearable.CapabilityApi.CapabilityListener,%20android.net.Uri,%20int)">
315{@code CapabilityApi.addListener()}</a> to notify Google Play services that your activity is
316interested in listening for data layer events.</li>
317
318<li>In {@link android.app.Activity#onStop onStop()}, unregister any listeners with
319<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)"><code>DataApi.removeListener()</code></a>,
320
321<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.removeListener()</code></a>, or
322
323<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.CapabilityApi.CapabilityListener)">
324{@code CapabilityApi.removeListener()}</a>.</li>
325
326
327<p>An alternative to adding listeners in
328<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>
329and removing them in
330{@link android.app.Activity#onStop onStop()} is to add a filtered listener in an activity’s {@link android.app.Activity#onResume onResume()} and
331remove it in {@link android.app.Activity#onPause onPause()}, so as to only receive data that is relevant to the
332current application state.</p>
333
334
335<li>Implement
336<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.DataListener.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
337<code>onDataChanged()</code></a>,
338  <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.MessageListener.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)">
339  <code>onMessageReceived()</code></a>,
340  <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html#onCapabilityChanged(com.google.android.gms.wearable.CapabilityInfo)">
341{@code onCapabilityChanged()}</a>,
342or methods from <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html">
343Channel API listener methods</a>, depending on the interfaces that you implemented.</li>
344</ol>
345
346<p>Here's an example that implements
347<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>DataApi.DataListener</code></a>:</p>
348
349<pre>
350public class MainActivity extends Activity implements
351        DataApi.DataListener, ConnectionCallbacks, OnConnectionFailedListener {
352
353    private GoogleApiClient mGoogleApiClient;
354
355    &#64;Override
356    protected void onCreate(Bundle savedInstanceState) {
357        super.onCreate(savedInstanceState);
358
359        setContentView(R.layout.main);
360        mGoogleApiClient = new GoogleApiClient.Builder(this)
361                .addApi(Wearable.API)
362                .addConnectionCallbacks(this)
363                .addOnConnectionFailedListener(this)
364                .build();
365    }
366
367    &#64;Override
368    protected void onStart() {
369        super.onStart();
370        if (!mResolvingError) {
371            mGoogleApiClient.connect();
372        }
373    }
374
375    &#64;Override
376    public void onConnected(Bundle connectionHint) {
377        if (Log.isLoggable(TAG, Log.DEBUG)) {
378            Log.d(TAG, "Connected to Google Api Service");
379        }
380        Wearable.DataApi.addListener(mGoogleApiClient, this);
381    }
382
383    &#64;Override
384    protected void onStop() {
385        if (null != mGoogleApiClient && mGoogleApiClient.isConnected()) {
386            Wearable.DataApi.removeListener(mGoogleApiClient, this);
387            mGoogleApiClient.disconnect();
388        }
389        super.onStop();
390    }
391
392    &#64;Override
393    public void onDataChanged(DataEventBuffer dataEvents) {
394        for (DataEvent event : dataEvents) {
395            if (event.getType() == DataEvent.TYPE_DELETED) {
396                Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
397            } else if (event.getType() == DataEvent.TYPE_CHANGED) {
398                Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri());
399            }
400        }
401    }
402}
403</pre>
404<h3>Using Filters with Listener Activities</h3>
405<p>
406Just as you can specify intent filters for manifest-based
407<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html">
408<code>WearableListenerService</code></a> objects, you can also use intent filters when registering a
409listener through the Wearable API. The same rules are applicable to both
410API-based listeners manifest-based listeners.
411</p>
412
413<p>
414A common pattern is to register a listener with a specific path or path prefix
415in an activity’s {@link android.app.Activity#onResume onResume()} method, and to
416remove the listener in the activity’s {@link android.app.Activity#onPause onPause()} method.
417Implementing listeners in this fashion allows your application to more selectively receive events,
418improving its design and efficiency.
419</p>
420