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<DataItemResult>() { 43 @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 @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<service android:name=".DataLayerListenerService"> 223 <intent-filter> 224 <action android:name="com.google.android.gms.wearable.DATA_CHANGED" /> 225 <data android:scheme="wear" android:host="*" 226 android:path="/start-activity" /> 227 </intent-filter> 228</service> 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=<node_id>}. 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 @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 @Override 368 protected void onStart() { 369 super.onStart(); 370 if (!mResolvingError) { 371 mGoogleApiClient.connect(); 372 } 373 } 374 375 @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 @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 @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