这篇文章要达到的目标:

1.介绍在Android系统上实现蓝牙通信的过程中涉及到的概念。
2.在android系统上实现蓝牙通信的步骤。
3.在代码实现上的考虑。
4.例子代码实现(手持设备和蓝牙串口设备通信)。
 
1.介绍在Android系统上实现蓝牙通信的过程中使用到的类
BluetoothAdapter
Represents the local Bluetooth adapter (Bluetooth radio). The BluetoothAdapter is the entry-point for all Bluetooth interaction. Using this, you can discover other Bluetooth devices, query a list of bonded (paired) devices, instantiate a BluetoothDevice using a known MAC address, and create a BluetoothServerSocket to listen for communications from other devices.
BluetoothAdapter
      代表当前手机的蓝牙设备。
BluetoothDevice
Represents a remote Bluetooth device. Use this to request a connection with a remote device through a BluetoothSocket or query information about the device such as its name, address, class, and bonding state.
      代表要链接的蓝牙设备。通过这个类,用户就可以实现与两个蓝牙设备之间的链接(当前设备和被链接设备)。
BluetoothSocket
Represents the interface for a Bluetooth socket (similar to a TCP Socket). This is the connection point that allows an application to exchange data with another Bluetooth device via InputStream and OutputStream.
   在蓝牙设备的通信中,某个服务,用一个唯一的UUID标识,比如串口通信服务(通过蓝牙实现串口通信)的UUID是:"00001101-0000-1000-8000-00805F9B34FB".
     下述代码做的事情是:1.通过BluetoothDevice提供的方法,实现当前设备与目标设备的连接建立。2.使用1中获得的BluetoothSocket,进行实际的连接建立。3.然后,通过BluetoothSocket获取InputStream和OutputStream,就可以与目标设备进行通信;通过InputStream读取目标设备传递过来的信息;通过OutputStream,将数据写到目标设备。
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket ;
private final BluetoothDevice mmDevice ; public ConnectThread(BluetoothDevice device, boolean secure) {
mmDevice = device;
BluetoothSocket tmp = null ;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try { tmp = device.createRfcommSocketToServiceRecord( MY_UUID ); } catch (IOException e) {
Log. e( TAG,e);
}
mmSocket = tmp;
} public void run() {
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
try {
mmSocket .connect();
} catch (IOException e) {
// Close the socket
try {
mmSocket .close();
} catch (IOException e2) {
Log. e( TAG,e2);
}
connectionFailed();
return ;
}
synchronized (BluetoothService. this ) {
mConnectThread = null ;
}
// Start the connected thread
connected(mmSocket);
} public void cancel() {
try {
mmSocket .close();
} catch (IOException e) {
Log. e( TAG, "close() of connect " + mSocketType + " socket failed", e);
}
}
}
BluetoothServerSocket
Represents an open server socket that listens for incoming requests (similar to a TCP ServerSocket). In order to connect two Android devices, one device must open a server socket with this class. When a remote Bluetooth device makes a connection request to the this device, the BluetoothServerSocket will return a connected BluetoothSocket when the connection is accepted.
      在蓝牙通信建立的过程中,初始化时,结构是Server/Client。Server端创建一个BluetoothServerSocket,专门监听Client端发出的请求,并对监听到的请求进行接收。成功接收后,返回一个BluetoothSocket给Client端。Client端,使用BluetoothSocket与Server端进行通信。
      比如,手持设备和蓝牙串口通信设备通信,蓝牙串口设备是Server端,它监听来自Client端的链接请求。成功建立连接之后,Client端就可以与Server端进行通信。
      在Server/Client架构中,一定有一端是Server端。
      使用蓝牙进行双向通信时,则是连接的设备,既做Client端,又做Server端。
 
2.在android系统上实现蓝牙通信的步骤
 
1.setting up Bluetooth.
2.finding devices that are either paired or available in the local are.
3.connecting devices.
4.transferring data between devices.
 
 
3.代码实现上的考虑
 
 1) 首先检查设备的的蓝牙是否可用。onCreate()方法。
 2) 在蓝牙可用的基础下,检查蓝牙是否已经开启了;如果没有开启,则开启;如果开启了,则新建一个蓝牙通信服务。onStart()方法。
 3) 在蓝牙通信服务开启(和可用)的基础下,检查当前的服务状态,如果是没有建立任何连接的,则选择要链接的设备(寻找已经配对的设备;首先要在蓝牙程序中进行设备的配对),然后建立连接。onResume()方法。
 4) 接下来就可以使用蓝牙通信服务进行数据传递mService;蓝牙数据的接收,mService会通过Handler传递给UI线程。
 
其中:3),选择要链接的设备,在下面的代码中,是这样做的,从已经配对的蓝牙设备中选择名称是DeviceName的蓝牙设备,然后建立连接。所以,首先要在系统的蓝牙管理程序中,先与指定的设备进行配对,这样,程序才可以在已经配对的设备中找到名称是DeviceName的蓝牙设备。
如下图:
 
 
状态转换顺序:
onCreate()---->onStart(),如果没有启用,则进行启用----->onPause()---->onResume()
onCreate()---->onStart(),如果蓝牙已经启用了,则---->onResume().
 
public class MainActivity extends Activity implements View.OnClickListener {

  private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothService mService = null;
private BluetoothDevice mOnePairedDevice;
private final String DeviceName = "LILEI" ; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout. activity_main); mBluetoothAdapter = BluetoothAdapter. getDefaultAdapter();
if ( mBluetoothAdapter == null ) { Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG ).show();
finish();
}
....
} @Override
public void onStart() {
super.onStart(); if (! mBluetoothAdapter.isEnabled()) {
// Enable Bluetooth function
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE );
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} else if (mService == null) {
setupBluetoothService();
}
} @Override
public void onResume() {
super.onResume(); // Performing this check in onResume() covers the case in which BT was
// not enabled during onStart(), so we were paused to enable it...
// onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
if ( mService != null ) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if ( mService.getState() == BluetoothService.STATE_NONE) {
if (mOnePairedDevice == null) {
mOnePairedDevice = getASpecificPairedDevice(DeviceName );
}
if (mOnePairedDevice != null) {
mService.start(mOnePairedDevice );
} else {
Toast. makeText(this, "Not Found the paired Device." , Toast.LENGTH_LONG ).show();
} }
}
} @Override
public void onDestroy() {
super.onDestroy();
if ( mService != null ) {
mService.stop();
}
} @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) { case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
setupBluetoothService();
} else {
// User did not enable Bluetooth or an error occurred
Log. d(TAG, "BT not enabled");
Toast. makeText(this, R.string. bt_not_enabled_leaving, Toast.LENGTH_SHORT ).show();
finish();
}
}
} public void setupBluetoothService() {
mService = new BluetoothService(mHandler );
} private BluetoothDevice getASpecificPairedDevice(String name) {
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
if (name.equals(device.getName())) {
return device;
}
} } return null;
}
...
}
 
4.例子代码实现
  
     在确定了蓝牙可用,蓝牙开启,要链接的设备,这些信息之后,就可以建立连接,然后进行通信管理。
      下述代码的实现:
      1.当前服务的状态标识---有这种。根据状态标识执行不同的操作。
      2.ConnectedThread线程,会不断循环读取InputStream,即是读取连接设备传递过来的信息,若有信息,则通过Handler传递给UI线程;当要对连接设备传递信息的时候,调用ConnectedThread暴露的public方法,write( byte [] buffer),writeFileMessage( byte [] buffer),writeFileStream(InputStream input).传递信息给连接设备时,使用OutputStream。
   要关闭与连接设备的通信,则调用暴露方法cancle(),即是调用BluetoothSocket的close()方法。
    3.在初始化服务时,使用ConnectThread来建立与目标设备的链接,获取BluetoothSocket.因为BluetoothSocket的connect方法是阻塞的,所以在独立的线程中执行,避免阻塞UI线程。
     服务的状态变化:
     初始化时,STATE_NONE;执行建立连接的操作时,STATE_CONNECTING;当已经和链接设备建立连接了,即是获取了BluetoothSocket,则标注状态STATE_CONNECTED;
     停止连接线程,读写线程之后,则标注状态为STATE_NONE。
 
public class BluetoothService {

    private static final String TAG = "BluetoothService" ;
private static final UUID MY_UUID = UUID.fromString( "00001101-0000-1000-8000-00805F9B34FB"); // Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device private final BluetoothAdapter mAdapter ;
private Handler mHandler ; private ConnectThread mConnectThread ;
private ConnectedThread mConnectedThread ; private int mState ; public BluetoothService(Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mHandler = handler; mState = STATE_NONE ; } public void setHandler(Handler handler) {
mHandler = handler;
} public void start(BluetoothDevice remoteDevice) {
connect(remoteDevice, false );
} public int getState() {
return mState ;
} public void stop() {
Log. d( TAG, "stop" ); if (mConnectThread != null) {
mConnectThread .cancel();
mConnectThread = null ;
} if (mConnectedThread != null) {
mConnectedThread .cancel();
mConnectedThread = null ;
}
setState( STATE_NONE ); } /**
* This thread runs while attempting to make an outgoing connection with a device. It runs
* straight through; the connection either succeeds or fails.
*/
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private String mSocketType ; public ConnectThread(BluetoothDevice device, boolean secure) {
mmDevice = device;
BluetoothSocket tmp = null ;
mSocketType = secure ? "Secure" : "Insecure"; // Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try { tmp = device.createRfcommSocketToServiceRecord( MY_UUID ); } catch (IOException e) {
Log. e( TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
mmSocket = tmp;
} public void run() {
Log. i( TAG, "BEGIN mConnectThread SocketType:" + mSocketType );
setName( "ConnectThread" + mSocketType ); // Always cancel discovery because it will slow down a connection
mAdapter .cancelDiscovery(); // Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket .connect();
} catch (IOException e) {
// Close the socket
try {
mmSocket .close();
} catch (IOException e2) {
Log. e( TAG, "unable to close() " + mSocketType
+ " socket during connection failure" , e2);
}
connectionFailed();
return ;
} // Reset the ConnectThread because we're done
synchronized (BluetoothService. this) {
mConnectThread = null ;
} // Start the connected thread
connected( mmSocket , mmDevice , mSocketType );
} public void cancel() {
try {
mmSocket .close();
} catch (IOException e) {
Log. e( TAG, "close() of connect " + mSocketType + " socket failed", e);
}
}
} /**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
// Send a failure message back to the Activity
Message msg = mHandler .obtainMessage(Constants. MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(Constants. TOAST , "Unable to connect device" );
msg.setData(bundle);
mHandler .sendMessage(msg); } /**
* Set the current state of the chat connection
*
* @param state An integer defining the current connection state
*/
private synchronized void setState( int state) {
Log. d( TAG, "setState() " + mState + " -> " + state);
mState = state; // Give the new state to the Handler so the UI Activity can update
mHandler .obtainMessage(Constants. MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
} /**
* Start the ConnectedThread to begin managing a Bluetooth connection
*
* @param socket The BluetoothSocket on which the connection was made
* @param device The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device,
final String socketType) {
Log. d( TAG, "connected, Socket Type:" + socketType); // Cancel the thread that completed the connection
if (mConnectThread != null) {
mConnectThread .cancel();
mConnectThread = null ;
} // Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread .cancel();
mConnectedThread = null ;
} // Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread .start(); // Send the name of the connected device back to the UI Activity
Message msg = mHandler .obtainMessage(Constants. MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(Constants. DEVICE_NAME , device.getName());
msg.setData(bundle);
mHandler .sendMessage(msg); setState( STATE_CONNECTED );
} /**
* This thread runs during a connection with a remote device. It handles all incoming and
* outgoing transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket, String socketType) {
Log. d( TAG, "create ConnectedThread: " + socketType);
mmSocket = socket;
InputStream tmpIn = null ;
OutputStream tmpOut = null ; // Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log. e( TAG, "temp sockets not created" , e);
} mmInStream = tmpIn;
mmOutStream = tmpOut;
} public void run() {
Log. i( TAG, "BEGIN mConnectedThread" );
byte [] buffer = new byte[3024];
int bytes; // Keep listening to the InputStream while connected
while (true ) {
try {
// Read from the InputStream
bytes = mmInStream .read(buffer); // Send the obtained bytes to the UI Activity
mHandler .obtainMessage(Constants. MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log. e( TAG, "disconnected" , e);
connectionLost(); break ;
}
}
} /**
* Write to the connected OutStream.
*
* @param buffer The bytes to write
*/
public void write( byte[] buffer) {
try {
mmOutStream .write(buffer); // Share the sent message back to the UI Activity
mHandler .obtainMessage(Constants. MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
} catch (IOException e) {
Log. e( TAG, "Exception during write" , e);
}
} public void writeFileMessage( byte[] buffer) {
try {
mmOutStream .write(buffer);
} catch (IOException e) {
Log. e( TAG, "Exception during write" , e);
}
} public void writeFileStream (InputStream input) {
byte [] buffer = new byte[1024];
int readLengh;
try {
while ((readLengh = input.read(buffer)) != -1) {
mmOutStream .write(buffer, 0, readLengh);
}
mHandler
.obtainMessage(Constants. MESSAGE_WRITE , -1, -1,
"Finish send file to remoteDevice." )
.sendToTarget(); } catch (IOException e) {
Log. e( TAG, "Exception during write" , e);
mHandler .obtainMessage(Constants. MESSAGE_WRITE, -1, -1,
"Error when send file to remoteDevice").sendToTarget();
} } public void cancel() {
try {
mmSocket .close();
} catch (IOException e) {
Log. e( TAG, "close() of connect socket failed" , e);
}
}
} /**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
// Send a failure message back to the Activity
Message msg = mHandler .obtainMessage(Constants. MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(Constants. TOAST , "Device connection was lost" );
msg.setData(bundle);
mHandler .sendMessage(msg); // Start the service over to restart listening mode } /**
* Start the ConnectThread to initiate a connection to a remote device.
*
* @param device The BluetoothDevice to connect
* @param secure Socket Security type - Secure (true) , Insecure (false)
*/
public synchronized void connect(BluetoothDevice device, boolean secure) {
Log. d( TAG, "connect to: " + device); // Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {
mConnectThread .cancel();
mConnectThread = null ;
}
} // Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread .cancel();
mConnectedThread = null ;
} // Start the thread to connect with the given device
mConnectThread = new ConnectThread(device, secure);
mConnectThread .start();
setState( STATE_CONNECTING );
} /**
* Write to the ConnectedThread in an unsynchronized manner
*
* @param out The bytes to write
* @see ConnectedThread#write(byte[])
*/
public void write( byte[] out, boolean isFile) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this ) {
if (mState != STATE_CONNECTED)
return ;
r = mConnectedThread ;
}
// Perform the write unsynchronized
if (isFile) {
r.writeFileMessage(out);
} else {
r.write(out);
} } public void write(InputStream in) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this ) {
if (mState != STATE_CONNECTED)
return ;
r = mConnectedThread ;
}
// Perform the write unsynchronized
r. writeFileStream(in);
}
}
参考资料:
http://developer.android.com/guide/topics/connectivity/bluetooth.html
http://blog.csdn.net/metalseed/article/details/7988945
 
    

Android蓝牙通信总结的更多相关文章

  1. Qt on Android 蓝牙通信开发

    版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载. 最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本 ...

  2. Android蓝牙通信具体解释

    蓝牙通信的大概过程例如以下: 1.首先开启蓝牙 2,搜索可用设备 3,创建蓝牙socket.获取输入输出流 4,读取和写入数据 5.断开连接关闭蓝牙 还要发送配对码发送进行推断! 以下是全部的源码:不 ...

  3. Android蓝牙通信

    Android为蓝牙设备之间的通信封装好了一些调用接口,使得实现Android的蓝牙通信功能并不困难.可通过UUID使两个设备直接建立连接. 具体步骤: 1. 获取BluetoothAdapter实例 ...

  4. (转)android 蓝牙通信编程

    转自:http://blog.csdn.net/pwei007/article/details/6015907 Android平台支持蓝牙网络协议栈,实现蓝牙设备之间数据的无线传输. 本文档描述了怎样 ...

  5. Android蓝牙通信功能开发

    1. 概述 Bluetooth 是几乎现在每部手机标准配备的功能,多用于耳机 mic 等设备与手机的连接,除此之外,还可以多部手机之间建立 bluetooth 通信,本文就通过 SDK 中带的一个聊天 ...

  6. android 蓝牙通信编程讲解

    以下是开发中的几个关键步骤: 1,首先开启蓝牙 2,搜索可用设备 3,创建蓝牙socket,获取输入输出流 4,读取和写入数据 5,断开连接关闭蓝牙 下面是一个demo 效果图: SearchDevi ...

  7. android 蓝牙 通信 bluetooth

    此例子基于 android demo Android的蓝牙开发,虽然不多用,但有时还是会用到,  Android对于蓝牙开发从2.0版本的sdk才开始支持,而且模拟器不支持,测试需要两部手机:     ...

  8. Android 蓝牙通信——AndroidBluetoothManager

    转载请说明出处! 作者:kqw攻城狮 出处:个人站 | CSDN To get a Git project into your build: Step 1. Add the JitPack repos ...

  9. Android BLE设备蓝牙通信框架BluetoothKit

    BluetoothKit是一款功能强大的Android蓝牙通信框架,支持低功耗蓝牙设备的连接通信.蓝牙广播扫描及Beacon解析. 关于该项目的详细文档请关注:https://github.com/d ...

随机推荐

  1. iOS开发NSDate详解

    1. 用于创建NSDate实例的类方法有 + (id)date; 返回当前时间 + (id)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs; 返回以 ...

  2. asp.net中Repeater结合js实现checkbox的全选/全不选

    前台界面代码: <input name="CheckAll" type="checkbox" id="CheckAll" value= ...

  3. 多个表单数据提交下的serialize()应用

    在实际开发场景中,难免遇到需要多个表单的数据传递问题. 之所以要进行多表单的数据传递是因为可以进行数据分组,便于数据的维护. 这个时候,出于不依赖jquery的考虑,有一个原生js函数来解决这个问题无 ...

  4. PHP中如何使用Redis接管文件存储Session详解

    https://www.jb51.net/article/151580.htm 前言 php默认使用文件存储session,如果并发量大,效率会非常低.而redis对高并发的支持非常好,可以利用red ...

  5. Qt编码设置

    1.Qt Creator -> 工具 -> 选项 -> 环境 - >概要 -> 语言    Qt Creator本身界面的语言选择,与cpp文件编码无关,与可执行文件显示 ...

  6. BZOJ 2241 打地鼠(特技暴力)

    果然暴力出奇迹.. O(n^2m^2)=1e8 536ms能过. 枚举锤子的长和宽,再验证是否可以满足条件并更新答案. 我们先从左上角为(1,1)的先锤,显然锤的次数是a[1][1]. 锤(i,j)的 ...

  7. BZOJ4565 HAOI2016字符合并(区间dp+状压dp)

    设f[i][j][k]为将i~j的字符最终合并成k的答案.转移时只考虑最后一个字符是由哪段后缀合成的.如果最后合成为一个字符特殊转移一下. 复杂度看起来是O(n32k),实际常数极小达到O(玄学). ...

  8. bzoj1208: [HNOI2004]宠物收养所 (sbt)

    切傻逼题还能wa那么多次我也是醉了 好啦其实是sbt都不会敲了(一直用神器treap) 重点是研究了下陈大神的删除,以前treap的删除都是直接旋转去删的…… 还是treap大法好&…… 题解 ...

  9. bzoj1588 [HNOI2002]营业额统计 (treap)

    平衡树裸题 只需要求前驱后驱 treap写法 const mm=<<; maxnumber=; maxn=; var left,right,fix,key:..maxn]of longin ...

  10. BZOJ4754 & 洛谷4323 & LOJ2072:[JSOI2016]独特的树叶——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4754 https://www.luogu.org/problemnew/show/P4323 ht ...