zoukankan      html  css  js  c++  java
  • Android Wear开发

    http://developer.android.com/training/wearables/data-layer/events.html

      以下是本人在学习官方开发文档时的笔记,主要是翻译为主,并在中间会插入一些自己的总结与研究,希望对读者有所帮助.

    本文分为2大部分:
    Section1 : 如何获取数据通讯的结果.
    Section2 : 如何监听数据层中的数据事件.
    其中Section2分为2模块:
      1. 继承WearableListenerService;
      2. Activity实现数据接口.

    Section 1 : Wait for the Status of Data Layer Calls- 等待数据操作结果

      在进行数据通讯的时候,有时候会返回一个PendingResult对象,例如调用了putDataItem方法.一旦PendingResult对象被构建了,那么数据操作就会在后台队列中.你可以选择是否对这个操作结果进行处理.PendingResult对象可以让你获取到操作结果,无论是同步还是异步.

    Asynchronously waiting-异步等待

    若你是在UI线程中执行数据操作,那么小心阻塞问题.在这里可以使用回调监听的方式来实现异步等待:

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

    Synchronously waiting-同步等待

    若你在独立的后台服务进程中进行数据操作,那么可以使用同步等待的方式来处理操作结果,在获取到处理结果前都会阻塞住进程.

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

    Section 2 : Listen for Data Layer Events- 监听数据层事件

    因为在手机和手表的数据通讯同步的,所以通常需要监听一些重要的事件,如数据创建,消息接收,通讯的连接.

    监听数据通讯,可以通过以下两种方式实现:

    • 创建一个继承自WearableListenerService的Service
    • 创建一个实现了DataApi.DataListener数据接口的Activity

    1.With a WearableListenerService

    使用情景

      一般而言都会在手机端和手表端都构建一个这样的子类Service. 但如果哪一端对数据事件的监听处理没什么需求,那一端则无需构建.

      例如,你可以在手机端构建和传递数据给手表,手表则监听这些数据事件来更新自身界面.但手表端只是单方面的获取数据,不会对数据进行做任何修改,那么,手机端则无需监听数据通讯事件.

    方法介绍

    接下来是介绍WearableListenerService的一些重要事件方法:

    • onDataChanged() :增,删,改,这三种事件都会调用这个接口.并且是两端都会被触发调用.→双向
    • onMessageReceived():消息从一端发送,会调用另一端的接口.→单向
    • onPeerConnected() , onPeerDisconnected():当两端进行连接或者断开的时候会触发.改变一端的连接状态都会调用两端的接口.→双向

    实现步骤

    1. 继承WearableListenerService
    2. 监听数据通讯事件
    3. 在Manifest中声明,并添加intent filter监听com.google.android.gms.wearable.BIND_LISTENER这个动作

    代码样例

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

    注解 :

    1. final List events = FreezableUtils .freezeIterable(dataEvents); 

      这里的作用是通过工具类FreezableUtils将数据对象dataEvents转换成不可修改的类型,以避免在处理数据的过程中,数据发生改变.

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

      阻塞当前线程,在30秒内获取连接状态,否则视为超时连接.因为onDataChange属于异步线程中,所以这里不会导致主线程阻塞.注意区分,这里是获取和googleApiClient的连接,而Section One中是发送数据的结果.

    Manifest声明

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

    Permissions within Data Layer Callbacks

    注意点

    数据回调接口中的权限问题
      为了回调数据事件接口,Google Play会绑定你的Service并且通过IPC的方式调用.这也导致了你的回调接口继承了调用进程的权限.
    若想要在回调接口中做某些特权操作,你会发现安全验证失败了,你会发现回调接口中打印出来的进程id,是在触发回调接口的进程的id,而不是你的应用的进程.
      为了解决这个问题,先调用clearCallingIdentity()来重置id,恢复为应用进程id;再执行你所需要的操作;最后再调用恢复为restoreCallingIdentity()调用者的id.

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

    WearableListenerService的深入研究:

    以下关于生命周期的测试环境是在模拟器上,在其他环境上可能略有差异.

    1. 生命周期 :完全由Android Wear控制 !
    • 前提 : 在Manifest中进行了声明,监听了com.google.android.gms.wearable.BIND_LISTENER这个Action
    • 现象 : 在手表和手机断开的情况下,安装了Demo,Service没有调用onCreate方法.当连接上,则立即调用onCreate方法.
    • 生命周期流程:
      连接手机 : onCreate > onPeerConnected
      操作过程 : 若Service没有接收到消息,以最后一次被回调为准,约8~12秒左右后会自杀,调用onDestroy.
      断开手机 : 若Service已死 : onCreate > onPeerDisconnected > onDestroy(等待8~12秒);若Service处于活跃状态,则调用后面2个方法.
    1. 自身已经实现了DataApi.DataListener,MessageApi.MessageListener,NodeApi.NodeListener这3个接口.

    总结 :

     1.WearableListenerService是由Android Wear控制;
    
     2.生命周期较短,在停止操作8~12秒内消亡
    
     3.不能理解为手机端和手表端的连接,而应该是理解为监听这个连接 : 因为断开两端的连接,不会立刻调用onDestroy方法
    
     4.在连接后台发生状态改变,会被立即地创建,调用回调接口,以处理应用业务
    

    2.With a Listener Activity

    方法介绍

    若你的应用只是需要在用户打开时监听数据通讯事件,而不需要在后台监听数据改变,那么可以实现以下接口来实现你的需求.

    • DataApi.DataListener
    • MessageApi.MessageListener
    • NodeApi.NodeListener

    实现步骤

    接下来是创建一个监听数据通讯事件的Activity

    1. 实现接口 : 实现上面列举的接口(根据需求来定,不需要全部都实现)
    2. 创建服务对象 : 在onCreate方法中创建一个GoogleApiClient对象来实现与数据通讯的连接.
    3. 连接服务 : 在onStart方法中调用GoogleApiClient的connect方法来连接服务
    4. 注册监听器 : 当GoogleApiClient连接上了服务,会回调onConnected方法,那么我们就可以在这里中注册监听器,来监听我们所关心的通讯事件.
    5. 反注册监听器,并断开服务 : 在onStop方法中,反注册之前注册的监听器,然后再断开GoogleApiClient服务连接.
    6. 实现事件回调接口 : 根据注册的监听器实现接口,处理相关的需求.

    代码样例

    以下是一个实现了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());
                }
            }
        }
    

    版权声明:欢迎自由转载-非商用-非衍生-保持署名。作者:Benhero,博客地址:http://www.cnblogs.com/benhero/

  • 相关阅读:
    周末之个人杂想(十三)
    PowerTip of the DaySorting Multiple Properties
    PowerTip of the DayCreate Remoting Solutions
    PowerTip of the DayAdd Help to Your Functions
    PowerTip of the DayAcessing Function Parameters by Type
    PowerTip of the DayReplace Text in Files
    PowerTip of the DayAdding Extra Information
    PowerTip of the DayPrinting Results
    Win7下IIS 7.5配置SSAS(2008)远程访问
    PowerTip of the DayOpening Current Folder in Explorer
  • 原文地址:https://www.cnblogs.com/benhero/p/4138551.html
Copyright © 2011-2022 走看看