android 藍芽模組Bluetooth 使用 十六進位制資料傳送
一個藍芽模組看起來很小,弄起來還是有點複雜的,從網上找了一個示例程式碼,http://blog.csdn.net/vnanyesheshou/article/details/51554852但是不能直接用,需要自己進行閱讀理解和修改後才能使用。
先貼一張自制的uml圖:
從圖中不難看出涉及的類還是挺多的,大致上分為裝置初始化、建立連線、傳送訊息三個大致的步驟吧。網上的程式碼封裝成了一個BluetoothChatUtil實用的類,負責建立通訊和傳送訊息,然後通過訊息的方式讓介面顯示獲取到的資料。BroadcastReceiver負責接收藍芽掃描時獲取到的裝置,由於專案中的目標藍芽是已經繫結的,所以直接使用BluetoothAdapter類的getBondedDevices()函式來獲取已經繫結的藍芽裝置,然後通過設定名稱或者地址來進行連線。
為現有專案新增藍芽模組的步驟大致如下(簡單地從程式碼出發):
(1)增加成員變數:
//獲取訊息的Handler
Handler mHandler;
//藍芽模組
//待連線的藍芽名稱
publicstatic final String BLUETOOTH_NAME = "XXXX";
//連線 msg
publicstatic final String OPEN_BLUE_HEX_STRING = "00 00 00 00 ";
//關閉 msg
publicstatic final String CLOSE_BLUE_HEX_STRING = "FF FF FF FF";
//待連線的藍芽地址
privateString mBluetoothAddress = "XX:XX:XX:XX:XX:XX";
boolean hasregister = false;
private ProgressDialog mProgressDialog;
//藍芽通訊模組
privateBluetoothChatUtil mBlthChatUtil;
//當前activity的控制代碼
privateContext mContext;
privateint REQUEST_ENABLE_BT = 1;
(2)onCreate中初始化:
mContext = this;
mProgressDialog= new ProgressDialog(this);
在handleMessage(Message msg)中捕獲幾個訊息:
//連線成功
caseBluetoothChatUtil.STATE_CONNECTED:
if(mProgressDialog.isShowing()){
mProgressDialog.dismiss();
}
StringdeviceName = msg.getData().getString(BluetoothChatUtil.DEVICE_NAME);
//mBtnBluetoothConnect.setText("已成功連線到裝置"+ deviceName);
Toast.makeText(getApplicationContext(),"連線成功:"+deviceName, Toast.LENGTH_SHORT).show();
//連線後就傳送你需要傳送的訊息
sendBluetoothMessage(OPEN_BLUE_HEX_STRING);
break;
//連線失敗
caseBluetoothChatUtil.STATAE_CONNECT_FAILURE:
if(mProgressDialog.isShowing()){
mProgressDialog.dismiss();
}
Toast.makeText(getApplicationContext(),"連線失敗", Toast.LENGTH_SHORT).show();
break;
//斷開連線
caseBluetoothChatUtil.MESSAGE_DISCONNECTED:
if(mProgressDialog.isShowing()){
mProgressDialog.dismiss();
}
//mBtnBluetoothConnect.setText("與裝置斷開連線");
break;
//收到訊息
caseBluetoothChatUtil.MESSAGE_READ:
byte[]buf = msg.getData().getByteArray(BluetoothChatUtil.READ_MSG);
Stringstr = new String(buf,0,buf.length);
Toast.makeText(getApplicationContext(),"讀成功" + str, Toast.LENGTH_SHORT).show();
break;
例項化通訊模組,並連線藍芽:
//藍芽模組
mBlthChatUtil= BluetoothChatUtil.getInstance(mContext);
mBlthChatUtil.registerHandler(mHandler);
initBluetooth();
//根據自己的需求來選擇需不需要掃描裝置
//mBluetoothAdapter.startDiscovery();
//連線裝置
connect();
if (mBlthChatUtil.getState() == BluetoothChatUtil.STATE_NONE) {
//啟動藍芽聊天服務
mBlthChatUtil.start();
}
藍芽初始化函式initBluetooth()和connect函式:
private void initBluetooth() {
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null) {//裝置不支援藍芽
Toast.makeText(getApplicationContext(),"裝置不支援藍芽", Toast.LENGTH_LONG).show();
finish();
return;
}
//判斷藍芽是否開啟
if(!mBluetoothAdapter.isEnabled()) {//藍芽未開啟
IntentenableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent,REQUEST_ENABLE_BT);
//開啟藍芽
mBluetoothAdapter.enable();
}
//
IntentFilterfilter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
//registerReceiver(mBluetoothReceiver,filter);
//hasregister= true;
if(mBluetoothAdapter.isEnabled()) {
intnMode = mBluetoothAdapter.getScanMode();
if(nMode== BluetoothAdapter.SCAN_MODE_CONNECTABLE){
Log.e(TAG_BLUE,"getScanMode= SCAN_MODE_CONNECTABLE");
}
if(nMode== BluetoothAdapter.SCAN_MODE_NONE){
Log.e(TAG_BLUE,"getScanMode= SCAN_MODE_NONE");
}
if(nMode== BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE){
Log.e(TAG_BLUE,"getScanMode= SCAN_MODE_CONNECTABLE_DISCOVERABLE");
}
//if(nMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
// IntentdiscoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
// discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);
// startActivity(discoverableIntent);
//}
}
//本身藍芽的名稱和地址
Stringname = mBluetoothAdapter.getName();
Stringaddress = mBluetoothAdapter.getAddress();
Log.d(TAG_BLUE,"bluetoothname ="+name+" address ="+address);
}
publicvoid connect() {
Set<BluetoothDevice>device = mBluetoothAdapter.getBondedDevices();
if(device.size()>0){ //存在已經配對過的藍芽裝置
for(Iterator<BluetoothDevice>it=device.iterator();it.hasNext();){
BluetoothDevicebtd=it.next();
String name = btd.getName();
String address =btd.getAddress();
String nameString =btd.getName()+'\n'+btd.getAddress();
Log.e(TAG_BLUE,"getBondedDevices :" + nameString);
//if(name != null &&name.equals(BLUETOOTH_NAME)){
if(address != null &&address.equals(mBluetoothAddress)){
mBlthChatUtil.connect(btd);
break;
//Toast.makeText(mContext,"連線成功", Toast.LENGTH_SHORT).show();
}
}
}else{ //不存在已經配對過的藍芽裝置
Log.e(TAG,"No can bematched to use bluetooth");
}
}
十六進位制資料轉換HexCommandtoByte和訊息傳送函式sendBluetoothMessage:
// 十六進位制的字串轉換成byte陣列
public static byte[]HexCommandtoByte(byte[] data) {
if (data == null) {
return null;
}
int nLength = data.length;
String strTemString = new String(data, 0, nLength);
String[] strings = strTemString.split(" ");
nLength = strings.length;
data = new byte[nLength];
for (int i = 0; i < nLength; i++) {
if (strings[i].length() != 2) {
data[i] = 00;
continue;
}
try {
data[i] =(byte)Integer.parseInt(strings[i], 16);
} catch (Exception e) {
data[i] = 00;
continue;
}
}
return data;
}
public void sendBluetoothMessage(Stringmessagesend){
Log.e(TAG_BLUE,"sendmessage : " + messagesend);
byte[] sendByte =HexCommandtoByte(messagesend.getBytes());
//mBlthChatUtil.write(messagesend.getBytes());
mBlthChatUtil.write(sendByte);
}
(3)在返回onBackPressed()或者onDestroy()傳送關閉藍芽訊息,並登出藍芽:
//關閉
sendBluetoothMessage(CLOSE_BLUE_HEX_STRING);
if(mBluetoothAdapter!=null &&mBluetoothAdapter.isDiscovering()){
mBluetoothAdapter.cancelDiscovery();
}
if (mBlthChatUtil.getState() !=BluetoothChatUtil.STATE_CONNECTED) {
Toast.makeText(mContext,"藍芽未連線", Toast.LENGTH_SHORT).show();
}else {
mBlthChatUtil.stop();
}
BluetoothChatUtil.java內容如下:
package XXX;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
這類做所有的工作,建立和管理藍芽
*連線其他裝置。它有一個執行緒,監聽
*傳入連線,螺紋連線裝置,和一個
*執行資料傳輸線連線時。
*/
public class BluetoothChatUtil {
// 除錯
private static final String TAG = "BluetoothChatService";
private static final boolean D = true;
// 名社民黨記錄當建立伺服器套接字
private static final String NAME = "BluetoothChat";
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public static StringBuffer hexString = new StringBuffer();
// 介面卡成員
private final BluetoothAdapter mAdapter;
private Handler mHandler;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
private static BluetoothChatUtil mBluetoothChatUtil;
private BluetoothDevice mConnectedBluetoothDevice;
//常數,指示當前的連線狀態
public static final int STATE_NONE = 0; // 當前沒有可用的連線
public static final int STATE_LISTEN = 1; // 現在偵聽傳入的連線
public static final int STATE_CONNECTING = 2; // 現在開始傳出聯絡
public static final int STATE_CONNECTED = 3; // 現在連線到遠端裝置
public static final int STATAE_CONNECT_FAILURE = 4;
public static boolean bRun = true;
public static final int MESSAGE_DISCONNECTED = 5;
public static final int STATE_CHANGE = 6;
public static final String DEVICE_NAME = "device_name";
public static final int MESSAGE_READ = 7;
public static final int MESSAGE_WRITE= 8;
public static final String READ_MSG = "read_msg";
/**
* 建構函式。準備一個新的bluetoothchat會話。
* @param context 使用者介面活動的背景
*/
private BluetoothChatUtil(Context context) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
}
public static BluetoothChatUtil getInstance(Context c){
if(null == mBluetoothChatUtil){
mBluetoothChatUtil = new BluetoothChatUtil(c);
}
return mBluetoothChatUtil;
}
public void registerHandler(Handler handler){
mHandler = handler;
}
public void unregisterHandler(){
mHandler = null;
}
/**
* 設定當前狀態的聊天連線
* @param state 整數定義當前連線狀態
*/
private synchronized void setState(int state) {
if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
// 給新狀態的處理程式,介面活性可以更新
mHandler.obtainMessage(STATE_CHANGE, state, -1).sendToTarget();
}
/**
* 返回當前的連線狀態。 */
public synchronized int getState() {
return mState;
}
public BluetoothDevice getConnectedDevice(){
return mConnectedBluetoothDevice;
}
/**
* 開始聊天服務。特別acceptthread開始 開始
* 會話聽力(伺服器)模式。所謂的活動onresume() */
public synchronized void start() {
if (D) Log.d(TAG, "start");
//取消任何執行緒試圖建立連線
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// 取消任何執行緒正在執行的連線
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// 啟動執行緒來聽一個bluetoothserversocket
if (mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
setState(STATE_LISTEN);
}
//連線按鍵響應函式
/**
* 開始connectthread啟動連線到遠端裝置。
* @param 裝置連線的藍芽裝置
*/
public synchronized void connect(BluetoothDevice device) {
if (D) Log.d(TAG, "connect to: " + device);
// 取消任何執行緒試圖建立連線
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
}
// 取消任何執行緒正在執行的連線
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
//啟動執行緒連線的裝置
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
/**
* 開始connectedthread開始管理一個藍芽連線
* @param bluetoothsocket插座上連線了
* @param 裝置已連線的藍芽裝置
*/
@SuppressWarnings("unused")
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
if (D) Log.d(TAG, "connected");
// 取消執行緒完成連線
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
//取消任何執行緒正在執行的連線
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// 取消接受執行緒只因為我們要連線到一個裝置
if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
// 啟動執行緒管理連線和傳輸
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
//把名字的連線裝置到Activity
mConnectedBluetoothDevice = device;
Message msg = mHandler.obtainMessage(STATE_CONNECTED);
Bundle bundle = new Bundle();
bundle.putString(DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
/**
* 停止所有的執行緒
*/
public synchronized void stop() {
if (D) Log.d(TAG, "stop");
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
setState(STATE_NONE);
//start();
}
/**
* Write to the ConnectedThread in an unsynchronized manner
* @param out The bytes to write
* @see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
//建立臨時物件
ConnectedThread r;
// 同步副本的connectedthread
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
// 執行寫同步
r.write(out);
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
setState(STATE_LISTEN);
// 傳送失敗的資訊帶回活動
Message msg = mHandler.obtainMessage(STATAE_CONNECT_FAILURE);
mHandler.sendMessage(msg);
mConnectedBluetoothDevice = null;
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
setState(STATE_LISTEN);
// 傳送失敗的資訊帶回Activity
Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECTED);
mHandler.sendMessage(msg);
mConnectedBluetoothDevice = null;
stop();
}
/**
*本線同時偵聽傳入的連線。它的行為
*喜歡一個伺服器端的客戶端。它執行直到連線被接受
*(或取消)。
*/
private class AcceptThread extends Thread {
// 本地伺服器套接字
private final BluetoothServerSocket mServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// 建立一個新的偵聽伺服器套接字
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mServerSocket = tmp;
}
public void run() {
if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
// 迴圈,直到連線成功
while (mState != STATE_CONNECTED) {
try {
// 這是一個阻塞呼叫和將只返回一個
// 成功的連線或例外
socket = mServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
// 如果連線被接受
if (socket != null) {
synchronized (BluetoothChatUtil.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// 正常情況。啟動連線螺紋。
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
// 沒有準備或已連線。新插座終止。
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D) Log.i(TAG, "END mAcceptThread");
}
public void cancel() {
if (D) Log.d(TAG, "cancel " + this);
try {
mServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
}
}
}
/**
* 本線在試圖使傳出聯絡
*與裝置。它徑直穿過連線;或者
*成功或失敗。
*/
private class ConnectThread extends Thread {
private BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// 得到一個bluetoothsocket
try {
mmSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
mmSocket = null;
}
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
mAdapter.cancelDiscovery();
// 使一個連線到bluetoothsocket
try {
// socket 連線
mmSocket.connect();
} catch (IOException e) {
connectionFailed();
//關閉這個socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
// 啟動服務在重新啟動聆聽模式
BluetoothChatUtil.this.start();
return;
}
// 因為我們所做的connectthread復位
synchronized (BluetoothChatUtil.this) {
mConnectThread = null;
}
// 啟動連線執行緒
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
/**
* 本線在連線與遠端裝置。
* 它處理所有傳入和傳出的傳輸。
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// 獲得bluetoothsocket輸入輸出流
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "沒有建立臨時sockets", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
int bytes;
// 繼續聽InputStream同時連線
while (true) {
try {
byte[] buffer = new byte[1024];
// 讀取輸入流
bytes = mmInStream.read(buffer);
// 傳送獲得的位元組的使用者介面
Message msg = mHandler.obtainMessage(MESSAGE_READ);
Bundle bundle = new Bundle();
bundle.putByteArray(READ_MSG, buffer);
msg.setData(bundle);
mHandler.sendMessage(msg);
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
/**
* 寫輸出的連線。
* @param buffer 這是一個位元組流
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// 分享傳送的資訊到Activity
mHandler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}