Android 處理數據層的事件

2018-08-02 17:54 更新

編寫:wly2014 - 原文: http://developer.android.com/training/wearables/data-layer/events.html

當做出數據層上的調用時,我們可以得到它完成后的調用狀態(tài),也可以用監(jiān)聽器監(jiān)聽到調用最終實現(xiàn)的改變。

等待數據層調用的狀態(tài)

注意到,調用數據層API,有時會返回 PendingResult,如 putDataItem()PendingResult 一被創(chuàng)建,操作就會在后臺排列等候。之后我們若無動作,這些操作最終會默默完成。然而,通常要處理操作完成后的結果,PendingResult 能夠讓我們同步或異步地等待結果。

異步調用

若代碼運行在主UI線程上,不要讓數據層API調用阻塞UI。我們可以增加一個回調到 PendingResult 對象來運行異步調用,該回調函數將在操作完成時觸發(fā)。

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的情況),則調用導致的阻塞沒影響。在這種情況下,我們可以用 PendingResult對象調用await()),它將阻塞至請求完成,并返回一個Result對象:

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

監(jiān)聽數據層事件

因為數據層在手持和可穿戴設備間同步并發(fā)送數據,所以通常要監(jiān)聽重要事件,例如創(chuàng)建數據元,接收消息,或連接可穿戴設備和手機。

對于監(jiān)聽數據層事件,有兩種選擇:

通過這兩種選擇,為我們感興趣的事件重寫數據事件回調方法。

使用 WearableListenerService

通常,我們在手持設備和可穿戴設備上都創(chuàng)建該 service 的實例。如果我們不關心其中一個應用中的數據事件,就不需要在相應的應用中實現(xiàn)此 service。

例如,我們可以在一個手持設備應用程序上操作數據元對象,可穿戴設備應用監(jiān)聽這些更新來更新自身的UI。而可穿戴不更新任何數據元,所以手持設備應用不監(jiān)聽任何可穿戴式設備應用的數據事件。

我們可以用 WearableListenerService 監(jiān)聽如下事件:

  • onDataChanged()) - 當數據元對象創(chuàng)建,更改,刪除時調用。一連接端的事件將觸發(fā)兩端的回調方法。
  • onMessageReceived()) - 消息從一連接端發(fā)出,在另一連接端觸發(fā)此回調方法。
  • onPeerConnected()) 和 onPeerDisconnected()) - 當與手持或可穿戴設備連接或斷開時調用。一連接端連接狀態(tài)的改變會在兩端觸發(fā)此回調方法。

創(chuàng)建WearableListenerService,我們需要:

  1. 創(chuàng)建一個繼承自 WearableListenerService 的類。
  2. 監(jiān)聽我們關心的事件,比如 onDataChanged())。
  3. 在Android manifest中聲明一個intent filter,把我們的 WearableListenerService 通知給系統(tǒng)。這樣允許系統(tǒng)在需要時綁定我們的 service。

下例展示如何實現(xiàn)一個簡單的 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 mainfest中相應的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調用回調方法。這樣的結果是,我們的回調方法繼承了調用進程的權限。

如果我們想在一個回調中執(zhí)行權限操作,安全檢查會失敗,因為回調是以調用進程的身份運行,而不是應用程序進程的身份運行。

為了解決這個問題,在進入IPC后使用 clearCallingIdentity()) 重置身份,當完成權限操作后,使用 restoreCallingIdentity()) 恢復身份:

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

使用一個Listener Activity

如果我們的應用只關心當用戶與應用交互時產生的數據層事件,并且不需要一個長時間運行的 service 來處理每一次數據的改變,那么我們可以在一個 activity 中通過實現(xiàn)如下一個和多個接口來監(jiān)聽事件:

創(chuàng)建一個 activity 監(jiān)聽數據事件,需要:

  1. 實現(xiàn)所需的接口。
  2. 在 onCreate(Bundle)) 中創(chuàng)建 GoogleApiClient 實例。
  3. 在 onStart()) 中調用 connect()) 將客戶端連接到 Google Play services。
  4. 當連接到Google Play services后,系統(tǒng)調用 onConnected())。這里是我們調用 DataApi.addListener(),MessageApi.addListener() 或 NodeApi.addListener(),以告知Google Play services 我們的 activity 要監(jiān)聽數據層事件的地方。
  5. 在 onStop()) 中,用 DataApi.removeListener()), MessageApi.removeListener())或NodeApi.removeListener()) 注銷監(jiān)聽。
  6. 基于我們實現(xiàn)的接口繼而實現(xiàn) onDataChanged(), onMessageReceived(), onPeerConnected()和 onPeerDisconnected()。

這是實現(xiàn)DataApi.DataListener的例子 :

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

    private GoogleApiClient mGoogleApiClient;

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


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號