Bluetooth LE(低功耗蓝牙) - 第二部分

原文地址 http://blog.csdn.net/likebamboo/article/details/26483375


回顾

     在前面的文章中我们介绍了Bluetooth LE的背景也说明了我们在本系列文章中将要开发什么,但是还没有实际的代码。我们将在这篇文章中纠正这一点,我们将通过定义 Service/Activity 架构来确保蓝牙操作从UI中解耦。

Service 与 Activity 通信

     在我们继续之前,我应该指出的是,我们不打算在这篇文章中去探究BLE的细节。起初,我们打算建立一个Activity并绑定Service,它将使我们能够把所有的蓝牙操作从UI中解耦,同时让我们从BLE接收到数据后更新UI。

     要做到这一点,我们将使用Messenger模式。它能够帮助我们不通过任何直接的方法调用而实现两个组件之间的通信。 Messenger模式要求每个组件来实现自身的Messenger实现:当类的实例被创建后处理传入的Message对象。Activity和Service的实现将运行在UI线程,但是我们将确保他们在各自的方法调用上彼此透明。

通过实现他们各自的Messenger实现以及在相应地方的逻辑处理,使我们的代码更容易理解和维护。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class BleService extends Service {  
  2.     public static final String TAG = "BleService";  
  3.     static final int MSG_REGISTER = 1;  
  4.     static final int MSG_UNREGISTER = 2;  
  5.     private final Messenger mMessenger;  
  6.     private final List<Messenger> mClients =   
  7.         new LinkedList<Messenger>();  
  8.   
  9.     public BleService() {  
  10.         mMessenger = new Messenger(  
  11.             new IncomingHandler(this));  
  12.     }  
  13.   
  14.     @Override  
  15.     public IBinder onBind(Intent intent) {  
  16.         return mMessenger.getBinder();  
  17.     }  
  18.   
  19.     private static class IncomingHandler extends Handler {  
  20.         private final WeakReference<BleService> mService;  
  21.   
  22.         public IncomingHandler(BleService service) {  
  23.             mService = new WeakReference<BleService>(service);  
  24.         }  
  25.   
  26.         @Override  
  27.         public void handleMessage(Message msg) {  
  28.             BleService service = mService.get();  
  29.             if (service != null) {  
  30.                 switch (msg.what) {  
  31.                     case MSG_REGISTER:  
  32.                         service.mClients.add(msg.replyTo);  
  33.                         Log.d(TAG, "Registered");  
  34.                         break;  
  35.                     case MSG_UNREGISTER:  
  36.                         service.mClients.remove(msg.replyTo);  
  37.                         Log.d(TAG, "Unegistered");  
  38.                         break;  
  39.                     default:  
  40.                         super.handleMessage(msg);  
  41.                 }  
  42.             }  
  43.         }  
  44.     }  
  45. }  
     基本代码非常简单 但仍有 一些细微之处 值得 去解释

     首先,InnerHandler 声明为静态。不要试图以一个非静态内部类来实现这个,否则会泄漏内存(leaking memory),这可能非常严重。这是因为一个类的非静态内部类可以持有一个该类的实例,并可以直接访问其成员变量和方法。简单来说,Java垃圾收集器将不会破坏被其他对象引用的对象(实际上比这更复杂一点,但也足够解释所发生的情况)。该Handler的父类实例是一个Service对象(一个Android Context),所以如果有任意一个对象持有该Handler实例的引用,都将隐式地阻止该Service对象被垃圾回收掉。这就是所谓的“Context  leak (上下文泄漏)”。它也是一个非常糟糕的事情,因为上下文可能相当大。

(译者注:关于“Context Leak”更多的介绍请查看http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

   我们避免上下文泄漏的方法是始终将内部类声明为静态,if they are declared within classes which subclass Context (不知道该怎么翻译)。 这也意味着我们已经失去了使用内部类的一个主要优点:访问父类属性和(or或)方法的能力。但我们可以很容易地通过使用WeakReference(弱引用)来克服这一点。弱引用可以使我们保持对一个对象的引用,并且不会阻止它被垃圾回收机制回收。

 所以我们的InnerHandler类被构造成拥有一个包裹在WeakReference对象中的它父类的实例的引用。而不是直接拥有其父类的引用。这样InnerHandler可以调用 WeakReference 的get()方法获取其父类实例的引用。我们需要做一个null判断因为父类的实例如果垃圾回收那么该引用将为但如果它不为空,那么我们可以以与非静态内部类完全相同的方式使用该实例的引用

   另一件值得一提的事是,我们目前有两种类型的消息:注册和取消注册。这允许多个用户订阅Service发出的信息(Service会从我们的BLE设备中获得更新信息)。在我们的示例应用程序中只有Activity将从Service中得到更新信息,但在现实世界中应用程序可能有更多的组件所需要的数据,所以发布/订阅模型是合适的。

我们的Activity:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class BleActivity extends Activity {  
  2.     public static final String TAG = "BluetoothLE";  
  3.     private final Messenger mMessenger;  
  4.     private Intent mServiceIntent;  
  5.     private Messenger mService = null;  
  6.     private ServiceConnection mConnection =   
  7.         new ServiceConnection() {  
  8.         @Override  
  9.         public void onServiceConnected(ComponentName name,   
  10.             IBinder service) {  
  11.             mService = new Messenger(service);  
  12.             try {  
  13.                 Message msg = Message.obtain(null,   
  14.                     BleService.MSG_REGISTER);  
  15.                 if (msg != null) {  
  16.                     msg.replyTo = mMessenger;  
  17.                     mService.send(msg);  
  18.                 } else {  
  19.                     mService = null;  
  20.                 }  
  21.             } catch (Exception e) {  
  22.                 Log.w(TAG, "Error connecting to BleService",   
  23.                     e);  
  24.                 mService = null;  
  25.             }  
  26.         }  
  27.   
  28.         @Override  
  29.         public void onServiceDisconnected(ComponentName name) {  
  30.             mService = null;  
  31.         }  
  32.     };  
  33.   
  34.     public BleActivity() {  
  35.         super();  
  36.         mMessenger = new Messenger(new IncomingHandler(this));  
  37.     }  
  38.   
  39.     @Override  
  40.     protected void onCreate(Bundle savedInstanceState) {  
  41.         super.onCreate(savedInstanceState);  
  42.         setContentView(R.layout.activity_ble);  
  43.         mServiceIntent = new Intent(this, BleService.class);  
  44.     }  
  45.   
  46.     @Override  
  47.     protected void onStop() {  
  48.         if (mService != null) {  
  49.             try {  
  50.                 Message msg = Message.obtain(null,   
  51.                     BleService.MSG_UNREGISTER);  
  52.                 if (msg != null) {  
  53.                     msg.replyTo = mMessenger;  
  54.                     mService.send(msg);  
  55.                 }  
  56.             } catch (Exception e) {  
  57.                 Log.w(TAG,   
  58.                     "Error unregistering with BleService",  
  59.                      e);  
  60.                 mService = null;  
  61.             } finally {  
  62.                 unbindService(mConnection);  
  63.             }  
  64.         }  
  65.         super.onStop();  
  66.     }  
  67.   
  68.     @Override  
  69.     protected void onStart() {  
  70.         super.onStart();  
  71.         bindService(mServiceIntent, mConnection,   
  72.             BIND_AUTO_CREATE);  
  73.     }  
  74.   
  75.     private static class IncomingHandler extends Handler {  
  76.         private final WeakReference<BleActivity> mActivity;  
  77.   
  78.         public IncomingHandler(BleActivity activity) {  
  79.             mActivity =   
  80.                 new WeakReference<BleActivity>(activity);  
  81.         }  
  82.   
  83.         @Override  
  84.         public void handleMessage(Message msg) {  
  85.             BleActivity activity = mActivity.get();  
  86.             if (activity != null) {  
  87.                 //TODO: Do something  
  88.             }  
  89.             super.handleMessage(msg);  
  90.         }  
  91.     }  
  92. }  

      在Activity的onstart()和onstop()方法中绑定和解绑Service。 ServiceConnection 方法( 当Service 绑定和解除绑定 操作完成时回调)中 Activity‘s Messenger  则通过向Service Messenger 发送适当的消息实现 注册和反注册

     之后我们需要在Manifest中添加适当的声明(我没有将它展示在这里,但在源码中可以看到) 。我们有一个简单的Activity和Service配对,他们能够互相通信。如果我们运行这个app,它什么都没做但在logcat中显示了我们所期望的注册/注销工作

[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. com.stylingandroid.ble D/BleService﹕ Registered  
  2. com.stylingandroid.ble D/BleService﹕ Unegistered  

     所以现在我们拥有了一个app的框架,它使我们能够从Service中收集数据并更新我们的UI

下期预告

     抱歉,我们已经从上周没有包含代码的文章中脱离出来了,这周的文章中虽然包含代码却和本系列文章的主题(Bluetooth LE)不怎么相关。但是对学习BLE来现在是一个好的开始,在下一篇文章将开始把BLE与我们的发现结合在一起。

     这篇文章的源代码可以在 这里 找到。

-----------------------------------------------------不怎么华丽的分割线----------------------------------------------------------------------

原文链接:http://blog.stylingandroid.com/archives/2408

© 2014, Mark Allison. All rights reserved. This article originally appeared on Styling Android.

Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License   


  哦,好吧,也许我真不是学英语的料,这篇文章的翻译自己都觉得烂到渣渣啦,但无论怎么样,还是要继续。“英语虐我千百遍,我待英语如初恋”,欢迎各位网友指出文中的错误,免得误导了大家啊。努力ing...




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值