最近,花了几天时间搞了一下蓝牙实现双机通信,在此分享一下自己的制作过程,及遇到的相关问题。首先这篇博文将结合各个部分进行详细的说明,有便于后期新人学习,同时利于个人的温习巩固。
项目关键点:
大的结构组织:
Activity, Service, Thread, BroadcastReceiver,
蓝牙模块所用到的点:
BluetoothDevice,
BluetoothSocket,
BluetoothServerSocket,
BluetoothAdapter,
数据流的点:
ObjectInputStream,
ObjectOutputStream 。
接下来,项目所用到重点知识进行一一详解:
Activity:(活动)
首先理解定义:包含用户界面的组件,主要用于和用户进行交互。
了解其生命周期:
主要分为三个生存期:
完整生存期:onCreate()和onDestroy()方法之间的过程。
可见生存期:onStart()和onStop()方法之间的过程。
前台生存期:onResume()和onPause()方法之间的过程。
项目所用到的onCreate(),onStart(),onStop()。
onCreate():活动的一些初始化,例如按钮,TextView的初始化等。
onStart():活动由可见到不可见时调用,主要在此开启Service。
onStop():活动不可见时,主要是在此停止Service。
Service:(服务)
服务实现后台运行,就算活动被关了,服务照样运行,Service运行在程序进程的主线程中。
项目所用到的服务的生命周期函数:
startService()启动服务
onCreate(),onDestroy();
onCreate()方法是在服务被创建的时候执行,
stopSelf()或者stopService()停止服务。
onDestroy();注销服务。
Thread(线程)
BroadcastReceiver(广播接收器)
http://blog.csdn.net/huangbiao86/article/details/6668525
BluetoothSocket(客户端套接字)
所谓Socket,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。(摘自百度百科)
socket = serverDevice.createRfcommSocketToServiceRecord(BluetoothTools.RFCOMM_UUID);
socket.connect();
在服务器端,使用BluetoothServerSocket类创建一个监听服务端口,当一个连接被BluetoothServerSocket接受,会返回一个新的BluetoothSocket来管理该连接。客户端,使用一个单独的BluetoothSocket类去初始化一个外接连接和管理该连接。
使用的蓝牙端口是RFCOMM(面向连接,通过蓝牙模块进行数据流传输方式,也被称为串行端口规范SPP),
项目代码:
private BluetoothAdapter adapter;
private BluetoothSocket socket;//用于通信的Socket
private BluetoothServerSocket serverSocket;
serverSocket=adapter.listenUsingRfcommWithServiceRecord("Server"RFCOMM_UUID);
socket = serverSocket.accept();//接收到客户端的连接,转为BluetoothSocket进行通信
public static final UUID RFCOMM_UUID = UUID.fromString("36a274b5-be67-4782-a260-81586f26262a");
代码说明:
accept()方法是一个线程阻塞的,只有接受到客户端的连接,线程才会继续执行。
当然这个UUID是用代码自动生成的,只要客户端与服务端的UUID是一致的,两者就可以匹配成功。
在此注意一点,如果想让手机蓝牙APP连接单片机的蓝牙模块,UUID就是官方提供的通用码:
00001101-0000-1000-8000-00805F9B34FB
BluetoothAdapter(蓝牙适配器)
首先讲一下Adapter, 定义为将一个类的接口变换成客户端所期待的一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。BluetoothAdapter 可以初始化蓝牙设备的搜索,查询可匹配的设备集,使用一个已知的MAC地址来初始化一个BluetoothDevice类,创建一个BluetoothServerSocket类以监听其他设备对本机的连接请求。
IP地址专注于网络层,将数据包从一个网络转发到另外一个网络;而MAC地址专注于数据链路层,将一个数据帧从一个节点传送到相同链路的另一个节点。
具体代码的实现:
//搜索到的远程设备集合
private List discoveredDevices = new ArrayList();
//蓝牙适配器
private final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothAdapter.enable();//打开蓝牙
bluetoothAdapter.startDiscovery();//开始搜索
接下来介绍一下广播事件:
BluetoothAdapter.ACTION_DISCOVERY_STARTED 开启对远程设备的搜索
BluetoothDevice.ACTION_FOUND 发现远程设备
BluetoothAdapter.ACTION_DISCOVERY_FINISHED 搜索结束
ObjectInputStream
ObjectOutputStream
两个类读写的对象需要实现Serializable接口,何为Serializable,java提供的通用数据保存和读取的接口。至于从什么地方读出来和保存到哪里去都被隐藏在函数参数的背后。任何类型只要实现了Serializable接口,就可以被保存到文件中,或者作为数据流通过网络发送到别的地方。也可以用管道来传输到系统的其他程序中。
dataIntent.putExtra(DATA,(Serializable)msg.obj);
intent.getExtras().getSerializable(DATA);
private ObjectInputStream inStream; //对象输入流
private ObjectOutputStream outStream;//对象输出流
this.outStream = new ObjectOutputStream(socket.getOutputStream());
this.inStream = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
Object obj = inStream.readObject();//读取数据
//写入一个可序列化的对象
public void writeObject(Object obj) {
try {
/*
* Flush() 是清空,而不是刷新
* 主要用在IO中,即清空缓冲区数据,就是说你用读写流的时候,
* 其实数据是先被读到了内存中,然后用数据写到文件中,当你
* 数据读完的时候不代表你的数据已经写完了,因为还有一部分
* 有可能会留在内存这个缓冲区中。这时候如果你调用了 Close()
* 方法关闭了读写流,那么这部分数据就会丢失,所以应该在关闭
* 读写流之前先Flush(),先清空数据。
* */
outStream.flush();
outStream.writeObject(obj);
outStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
可能有些问题,请看客们给与意见。
参考书籍 android的
《第一行代码》郭霖 著
《android经典项目开发实战》王翠萍 著