데이터 계층 이벤트 처리


당신이 데이터 계층의 호출을 만들 때, 그것이 완료 되었을 때 호출의 상태를 받을 뿐만 아니라 리스너와의 호출이 종료되는 어떠한 변화들을 수신 할 수 있다.

데이터 계층 호출의 상태 대기


당신은 putDataItem()처럼 때때로 데이터 계층 API가 PendingResult를 반환하는 호출을 알 수 있다. PendingResult가 생성되자마자, 작업은 백그라운드에서 큐로 보관된다. 만약 당신이 이 이후에 아무것도 하지 않는다면, 작업은 결국 조용히 마무리 될 것이다. 하지만, 대개 당신은 작업이 완료된 후의 결과로 무언가를 원할 것이므로, 동기적 혹은 비동기적으로 PendingResult는 당신에게 결과 상태를 위해 기다리게 한다.

비동기적 대기

만약 당신의 코드가 메인 UI 스레드에서 실행중이라면, 데이터 계층 API에 블로킹 호출을 만들면 안된다. 당신은 작업이 완료되었을 때 발동하는 PendingResult 객체에 콜백을 추가함으로써 비동기적으로 호출을 실행할 수 있다:

pendingResult.setResultCallback(new ResultCallback<DataItemResult>() {
   
@Override
   
public void onResult(final DataItemResult result) {
       
if(result.getStatus().isSuccess()) {
           
Log.d(TAG, "Data item set: " + result.getDataItem().getUri());
       
}
   
}
});

동기적 대기

만약 당신의 코드가 백그라운드 서비스(WearableListenerService에서의 경우)에서 분리된 핸들러 스레드에서 실행중이라면, 호출을 블로킹 해도 괜찮다. 이 경우 당신은 요청이 완료될 때까지 블럭되고 Result 객체를 반환하는 PendingResult 객체에서 await()의 호출을 할수 있다:

DataItemResult result = pendingResult.await();
if(result.getStatus().isSuccess()) {
   
Log.d(TAG, "Data item set: " + result.getDataItem().getUri());
}

데이터 계층 이벤트 수신


데이터 계층은 동기화 및 휴대용 장치와 웨어러블 장치를 걸쳐 데이터를 전송하기 때문에, 보통 당신은 데이터 아이템이 언제 만들어졌는지, 메시지가 수신되었는지, 혹은 웨어러블과 휴대용 장치가 연결 되었을 때와 같은 중요한 이벤트의 수신을 원한다.

데이터 계층 이벤트의 수신을 위한, 두 가지 옵션이 있다:

이러한 두 옵션으로, 당신의 구현 내부에서 처리에 관심있는 데이터 이벤트 콜백들 중 오버라이드 한다.

WearableListenerService 사용

일반적으로 당신은 웨어러블과 휴대용 앱 두 곳 모두에서 이 서비스의 객체들을 생성한다. 만약 당신이 이들 앱중 하나에서 데이터 이벤트에 대해 신경쓰지 않는다면, 당신은 특정 앱에서 이 서비스를 구현할 필요가 없다.

예를들어, 당신은 데이터 아이템 객체를 sets & gets 하는 휴대용 앱과 UI의 업데이트를 하기 위해 그들의 최신 정보들을 수신하는 웨어러블 앱을 가질 수 있다. 웨어러블은 절대 데이터 아이템들을 업데이트 하지 않으므로, 휴대용 앱은 웨어러블 앱으로부터 어떠한 데이터 이벤트도 수신하지 않는다.

당신은 WearableListenerService로 다음 이벤트들의 수신할 수 있다:

  • onDataChanged() - 데이터 아이템 객체가 생성, 변경, 또는 삭제 될 때 호출된다. 연결의 한쪽 이벤트는 양쪽의 이 콜백을 발동시킨다.
  • onMessageReceived() - 연결의 한쪽으로부터 보내진 메시지는 다른쪽 연결의 이 콜백을 발동시킨다.
  • onPeerConnected()와 onPeerDisconnected() - 휴대용 혹은 웨어러블이 연결되거나 끊겼을때 호출된다. 연결의 한쪽에서 연결 상태의 변화는 연결 양쪽의 이들 콜백을 발동시킨다.

WearableListenerService를 생성하기 위해서는:

  1. WearableListenerService를 확장(extends)한 클래스를 생성하라.
  2. onDataChanged()와 같이 당신이 당신이 관심있어하는 이벤트를 수신하라.
  3. 당신의 WearableListenerService에 대한 시스템을 통지하기 위해 Android manifest 내부에서 intent filter를 선언하라. 이는 필요에 따라 당신의 서비스를 바인딩 하기 위한 시스템을 허용한다.

다음 예제는 간단한 WearableListenerService의 구현 방법을 보여준다:

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);
       
}
       
final List events = FreezableUtils
               
.freezeIterable(dataEvents);

       
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
               
.addApi(Wearable.API)
               
.build();

       
ConnectionResult connectionResult =
                googleApiClient
.blockingConnect(30, TimeUnit.SECONDS);

       
if (!connectionResult.isSuccess()) {
           
Log.e(TAG, "Failed to connect to GoogleApiClient.");
           
return;
       
}

       
// Loop through the events and send a message
       
/ to the node that created the data item.
       
for (DataEvent event : events) {
           
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.MessageApi.sendMessage(googleApiClient, nodeId,
                    DATA_ITEM_RECEIVED_PATH
, payload);
       
}
   
}
}

다음은 Android manifest 파일의 intent filter에 해당한다:

<service android:name=".DataLayerListenerService">
 
<intent-filter>
     
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
 
</intent-filter>
</service>

데이터 계층 콜백내의 권한

데이터 계층 이벤트를 위한 당신의 애플리케이션에 콜백을 제공하기 위해, Google Play services는 당신의 WearableListenerService에 바인딩하고, IPC를 통해 당신의 콜백을 호출한다. 이는 당신의 콜백들이 호출 프로세스의 권한을 상속받는다는 결과를 갖는다.

만약 당신이 콜백 내의 권한있는 작업을 수행하려고 할 경우, 당신의 콜백이 당신 앱의 프로세스의 신분 대신 호출 프로세스의 신분으로 실행중이기 때문에 보안 검사가 실패한다.

이를 수정하기 위해, IPC 경계를 횡단한 후 신분을 초기화하기 위한 clearCallingIdentity()를 호출한 뒤, 당신이 권한 있는 작업이 완료 되었을 때 restoreCallingIdentity()로 신분을 복원하라:

long token = Binder.clearCallingIdentity();
try {
    performOperationRequiringPermissions
();
} finally {
   
Binder.restoreCallingIdentity(token);
}

액티비티의 리스너 사용

만약 당신의 앱이 사용자가 앱과 상호작용하고 있으며 모든 데이터 변화 처리에 길게 실행되는 서비스가 필요없을 때 오직 데이터 계층 이벤트에만 관심이 있다면, 당신은 하나 혹은 그 이상의 다음 인터페이스들의 구현으로 액티비티 내에서 이벤트를 수신 할 수 있다.:

데이터 이벤트를 위한 리스너들의 액티비티 생성을 위해:

  1. 원하는 인터페이스들을 구현한다.
  2. onCreate(Bundle)에서, 데이터 계층 API로 작업할 수 있도록 GoogleApiClient의 객체를 생성한다.
  3. onStart()에서 Google Play services에 접속하기 위한 connect()를 호출한다.
  4. Google Play services에 연결이 설정되면, 시스템은 onConnected()를 호출한다. 이는 당신의 액티비티가 데이터 계층 이벤트의 수신에 관심있어하는 Google Play services의 통지를 위해 당신이 DataApi.addListener()MessageApi.addListener(), 혹은 NodeApi.addListener()를 호출한 곳이다.
  5. onStop()에서, DataApi.removeListener()MessageApi.removeListener(), 혹은 NodeApi.removeListener()로 리스너들을 해제한다.
  6. 당신이 구현했던 인터페이스들 따라 onDataChanged(), onMessageReceived()onPeerConnected(), 그리고 onPeerDisconnected()를 구현한다.

DataApi.DataListener를 구현한 예제가 있다:

public class MainActivity extends Activity implements
       
DataApi.DataListener, ConnectionCallbacks, OnConnectionFailedListener {

   
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);

        setContentView
(R.layout.main);
        mGoogleApiClient
= new GoogleApiClient.Builder(this)
               
.addApi(Wearable.API)
               
.addConnectionCallbacks(this)
               
.addOnConnectionFailedListener(this)
               
.build();
   
}

   
@Override
   
protected void onStart() {
       
super.onStart();
       
if (!mResolvingError) {
            mGoogleApiClient
.connect();
       
}
   
}

   
@Override
   
public void onConnected(Bundle connectionHint) {
       
if (Log.isLoggable(TAG, Log.DEBUG)) {
           
Log.d(TAG, "Connected to Google Api Service");
       
}
       
Wearable.DataApi.addListener(mGoogleApiClient, this);
   
}

   
@Override
   
protected void onStop() {
       
if (null != mGoogleApiClient && mGoogleApiClient.isConnected()) {
           
Wearable.DataApi.removeListener(mGoogleApiClient, this);
            mGoogleApiClient
.disconnect();
       
}
       
super.onStop();
   
}

   
@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());
           
}
       
}
   
}


'Android - Building Apps for Wearables > Sending and Syncing Data' 카테고리의 다른 글

Sending and Receiving Messages  (0) 2014.09.10
Transferring Assets  (0) 2014.09.10
Syncing Data Items  (0) 2014.09.10
Accessing the Wearable Data Layer  (0) 2014.09.10
Sending and Syncing Data  (0) 2014.09.10
Posted by 레미파
,