一.藍(lán)牙數(shù)據(jù)傳輸
藍(lán)牙數(shù)據(jù)傳輸其實(shí)跟我們的 Socket(套接字)有點(diǎn)類似,如果有不懂的等太,可以百度一下概念谅阿,我們只要知道是這么回事就可以了,在網(wǎng)絡(luò)中使用Socket和ServerSocket控制客戶端和服務(wù)端來(lái)數(shù)據(jù)讀寫丛晌。而藍(lán)牙通訊也是由客戶端和服務(wù)端來(lái)完成的,藍(lán)牙客戶端Socket是BluetoothSocket,藍(lán)牙服務(wù)端Socket是BluetoothServerSocket,這兩個(gè)類都在Android.bluetooth包下斗幼,而且無(wú)論是BluetoothSocket還是BluetoothServerSocket澎蛛,我們都需要一個(gè)UUID(標(biāo)識(shí)符),這個(gè)UUID在上篇也是有提到蜕窿,而且他的格式也是固定的:
UUID:XXXXXXXX(8)-XXXX(4)-XXXX(4)-XXXX(4)-XXXXXXXXXXXX(12)
第一段是8位谋逻,中間三段式4位,最后一段是12位桐经,UUID相當(dāng)于Socket的端口毁兆,而藍(lán)牙地址則相當(dāng)于Socket的IP
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="btnSearch"
android:text="搜索藍(lán)牙設(shè)備" />
<ListView
android:id="@+id/lvDevices"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
2.實(shí)現(xiàn)步驟
我們需要的東西
// 本地藍(lán)牙適配器? ??
private BluetoothAdapter mBluetoothAdapter;? ??
// 列表? ?
?private ListView lvDevices;? ??
// 存儲(chǔ)搜索到的藍(lán)牙? ??
private ListbluetoothDevices = new ArrayList();? ?
?// listview的adapter? ?
?private ArrayAdapterarrayAdapter;
// UUID.randomUUID()隨機(jī)獲取UUID
private final UUID MY_UUID = UUID
.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");
// 連接對(duì)象的名稱
private final String NAME = "LGL";
// 這里本身即是服務(wù)端也是客戶端,需要如下類
private BluetoothSocket clientSocket;
private BluetoothDevice device;
// 輸出流_客戶端需要往服務(wù)端輸出
private OutputStream os;
2.初始化
// 獲取本地藍(lán)牙適配器? ? ? ? ? ? ? ??
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();? ? ? ?
?// 判斷手機(jī)是否支持藍(lán)牙? ? ? ? ? ? ? ??
if (mBluetoothAdapter == null) {? ? ? ? ? ??
Toast.makeText(this, "設(shè)備不支持藍(lán)牙", Toast.LENGTH_SHORT).show();? ? ? ? ? ??
finish();? ? ? ??
}? ? ? ??
// 判斷是否打開(kāi)藍(lán)牙? ? ? ? ? ? ? ?
?if (!mBluetoothAdapter.isEnabled()) {? ? ? ? ? ?
?// 彈出對(duì)話框提示用戶是后打開(kāi)? ? ? ? ? ??
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);? ? ? ? ? ?
?startActivityForResult(intent, 1);? ? ? ? ? ?
?// 不做提示次询,強(qiáng)行打開(kāi)? ? ? ? ? ??
// mBluetoothAdapter.enable();? ? ? ?
?}? ? ? ?
?// 初始化listview? ? ? ?
?lvDevices = (ListView) findViewById(R.id.lvDevices);? ? ? ??
lvDevices.setOnItemClickListener(this);? ? ? ?
?// 獲取已經(jīng)配對(duì)的設(shè)備? ? ? ??
SetpairedDevices = mBluetoothAdapter.getBondedDevices();? ? ? ??
// 判斷是否有配對(duì)過(guò)的設(shè)備? ? ? ?
?if (pairedDevices.size() > 0) {? ? ? ? ? ?
?for (BluetoothDevice device : pairedDevices) {? ? ? ? ? ? ? ?
?// 遍歷到列表中? ? ? ? ? ? ? ?
?bluetoothDevices.add(device.getName() + ":" ?+ device.getAddress() + "\n");? ? ? ? ? ?
?}? ? ? ?
?}? ? ? ??
// adapter? ? ? ??
arrayAdapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1, android.R.id.text1,
bluetoothDevices);
lvDevices.setAdapter(arrayAdapter);
/**
* 異步搜索藍(lán)牙設(shè)備——廣播接收
*/
// 找到設(shè)備的廣播
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
// 注冊(cè)廣播
registerReceiver(receiver, filter);
// 搜索完成的廣播
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
// 注冊(cè)廣播
registerReceiver(receiver, filter);
}
3.點(diǎn)擊搜索
public void btnSearch(View v) {
// 設(shè)置進(jìn)度條
setProgressBarIndeterminateVisibility(true);
setTitle("正在搜索...");
// 判斷是否在搜索,如果在搜索荧恍,就取消搜索
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
// 開(kāi)始搜索
mBluetoothAdapter.startDiscovery();
}
4.搜索設(shè)備
private final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 收到的廣播類型
String action = intent.getAction();
// 發(fā)現(xiàn)設(shè)備的廣播
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 從intent中獲取設(shè)備
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 判斷是否配對(duì)過(guò)
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
// 添加到列表
bluetoothDevices.add(device.getName() + ":"
+ device.getAddress() + "\n");
arrayAdapter.notifyDataSetChanged();
}
// 搜索完成
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
.equals(action)) {
// 關(guān)閉進(jìn)度條
setProgressBarIndeterminateVisibility(true);
setTitle("搜索完成!");
}
}
};
5.客戶端實(shí)現(xiàn)已經(jīng)發(fā)送數(shù)據(jù)流
// 客戶端
@Override
public void onItemClick(AdapterView parent, View view, int position,
long id) {
// 先獲得藍(lán)牙的地址和設(shè)備名
String s = arrayAdapter.getItem(position);
// 單獨(dú)解析地址
String address = s.substring(s.indexOf(":") + 1).trim();
// 主動(dòng)連接藍(lán)牙
try {
// 判斷是否在搜索,如果在搜索屯吊,就取消搜索
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
try {
// 判斷是否可以獲得
if (device == null) {
// 獲得遠(yuǎn)程設(shè)備
device = mBluetoothAdapter.getRemoteDevice(address);
}
// 開(kāi)始連接
if (clientSocket == null) {
clientSocket = device
.createRfcommSocketToServiceRecord(MY_UUID);
// 連接
clientSocket.connect();
// 獲得輸出流
os = clientSocket.getOutputStream();
}
} catch (Exception e) {
// TODO: handle exception
}
// 如果成功獲得輸出流
if (os != null) {
os.write("Hello Bluetooth!".getBytes("utf-8"));
}
} catch (Exception e) {
// TODO: handle exception
}
}
6.Handler服務(wù)
// 服務(wù)端送巡,需要監(jiān)聽(tīng)客戶端的線程類
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
Toast.makeText(MainActivity.this, String.valueOf(msg.obj),
Toast.LENGTH_SHORT).show();
super.handleMessage(msg);
}
};
7.服務(wù)端讀取數(shù)據(jù)流
// 線程服務(wù)類
private class AcceptThread extends Thread {
private BluetoothServerSocket serverSocket;
private BluetoothSocket socket;
// 輸入 輸出流
private OutputStream os;
private InputStream is;
public AcceptThread() {
try {
serverSocket = mBluetoothAdapter
.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// 截獲客戶端的藍(lán)牙消息
try {
socket = serverSocket.accept(); // 如果阻塞了,就會(huì)一直停留在這里
is = socket.getInputStream();
os = socket.getOutputStream();
// 不斷接收請(qǐng)求,如果客戶端沒(méi)有發(fā)送的話還是會(huì)阻塞
while (true) {
// 每次只發(fā)送128個(gè)字節(jié)
byte[] buffer = new byte[128];
// 讀取
int count = is.read();
// 如果讀取到了盒卸,我們就發(fā)送剛才的那個(gè)Toast
Message msg = new Message();
msg.obj = new String(buffer, 0, count, "utf-8");
handler.sendMessage(msg);
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
8.開(kāi)啟服務(wù)
首先要聲明
//啟動(dòng)服務(wù)
ac =newAcceptThread();
ac.start();
MainActivity完整代碼
package com.lgl.bluetoothget;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice
;import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnItemClickListener {? ??
// 本地藍(lán)牙適配器? ??
private BluetoothAdapter mBluetoothAdapter;? ?
?// 列表? ?
?private ListView lvDevices;? ??
// 存儲(chǔ)搜索到的藍(lán)牙? ??
private ListbluetoothDevices = new ArrayList();? ?
?// listview的adapter? ?
?private ArrayAdapterarrayAdapter;? ?
?// UUID.randomUUID()隨機(jī)獲取UUID? ??
private final UUID MY_UUID = UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");? ?
?// 連接對(duì)象的名稱? ??
private final String NAME = "LGL";? ?
?// 這里本身即是服務(wù)端也是客戶端骗爆,需要如下類? ??
private BluetoothSocket clientSocket;? ??
private BluetoothDevice device;? ?
?// 輸出流_客戶端需要往服務(wù)端輸出? ??
private OutputStream os;? ?
?//線程類的實(shí)例? ??
private AcceptThread ac;? ??
@Override??
? protected void onCreate(Bundle savedInstanceState) {? ? ? ??
super.onCreate(savedInstanceState);? ? ? ??
setContentView(R.layout.activity_main);? ? ? ??
initView();? ??
}? ??
private void initView() {?
?? ? ? // 獲取本地藍(lán)牙適配器? ? ? ??
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();? ? ? ??
// 判斷手機(jī)是否支持藍(lán)牙 ? ? ??
if (mBluetoothAdapter == null) {? ? ? ? ? ??
Toast.makeText(this, "設(shè)備不支持藍(lán)牙", Toast.LENGTH_SHORT).show();? ? ? ? ? ??
finish();? ? ? ??
}? ? ? ??
// 判斷是否打開(kāi)藍(lán)牙? ? ? ??
if (!mBluetoothAdapter.isEnabled()) {? ? ? ? ? ??
// 彈出對(duì)話框提示用戶是后打開(kāi)? ? ? ? ? ?
?Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);? ? ? ? ? ??
startActivityForResult(intent, 1);? ? ? ? ? ?
?// 不做提示,強(qiáng)行打開(kāi)? ? ? ? ? ?
?// mBluetoothAdapter.enable();? ? ??
? }? ? ? ?
?// 初始化listview? ? ? ?
?lvDevices = (ListView) findViewById(R.id.lvDevices);? ? ? ?
?lvDevices.setOnItemClickListener(this);? ? ? ?
?// 獲取已經(jīng)配對(duì)的設(shè)備? ? ? ??
SetpairedDevices = mBluetoothAdapter.getBondedDevices();? ? ? ?
?// 判斷是否有配對(duì)過(guò)的設(shè)備? ? ? ?
?if (pairedDevices.size() > 0) {? ? ? ? ? ?
?for (BluetoothDevice device : pairedDevices) {? ? ? ? ? ? ? ?
?// 遍歷到列表中? ? ? ? ? ? ? ??
bluetoothDevices.add(device.getName() + ":" + device.getAddress() + "\n");? ? ? ? ? ?
?}? ? ? ?
?}? ? ? ??
// adapter ? ? ??
arrayAdapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1, android.R.id.text1,
bluetoothDevices);
lvDevices.setAdapter(arrayAdapter);
//啟動(dòng)服務(wù)
ac = new AcceptThread();
ac.start();
/**
* 異步搜索藍(lán)牙設(shè)備——廣播接收
*/
// 找到設(shè)備的廣播
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
// 注冊(cè)廣播
registerReceiver(receiver, filter);
// 搜索完成的廣播
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
// 注冊(cè)廣播
registerReceiver(receiver, filter);
}
public void btnSearch(View v) {
// 設(shè)置進(jìn)度條
setProgressBarIndeterminateVisibility(true);
setTitle("正在搜索...");
// 判斷是否在搜索,如果在搜索蔽介,就取消搜索
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
// 開(kāi)始搜索
mBluetoothAdapter.startDiscovery();
}
// 廣播接收器
private final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 收到的廣播類型
String action = intent.getAction();
// 發(fā)現(xiàn)設(shè)備的廣播
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 從intent中獲取設(shè)備
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 判斷是否配對(duì)過(guò)
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
// 添加到列表
bluetoothDevices.add(device.getName() + ":"
+ device.getAddress() + "\n");
arrayAdapter.notifyDataSetChanged();
}
// 搜索完成
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
.equals(action)) {
// 關(guān)閉進(jìn)度條
setProgressBarIndeterminateVisibility(true);
setTitle("搜索完成摘投!");
}
}
};
// 客戶端
@Override
public void onItemClick(AdapterView parent, View view, int position,
long id) {
// 先獲得藍(lán)牙的地址和設(shè)備名
String s = arrayAdapter.getItem(position);
// 單獨(dú)解析地址
String address = s.substring(s.indexOf(":") + 1).trim();
// 主動(dòng)連接藍(lán)牙
try {
// 判斷是否在搜索,如果在搜索,就取消搜索
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
try {
// 判斷是否可以獲得
if (device == null) {
// 獲得遠(yuǎn)程設(shè)備
device = mBluetoothAdapter.getRemoteDevice(address);
}
// 開(kāi)始連接
if (clientSocket == null) {
clientSocket = device
.createRfcommSocketToServiceRecord(MY_UUID);
// 連接
clientSocket.connect();
// 獲得輸出流
os = clientSocket.getOutputStream();
}
} catch (Exception e) {
// TODO: handle exception
}
// 如果成功獲得輸出流
if (os != null) {
os.write("Hello Bluetooth!".getBytes("utf-8"));
}
} catch (Exception e) {
// TODO: handle exception
}
}
// 服務(wù)端虹蓄,需要監(jiān)聽(tīng)客戶端的線程類
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
Toast.makeText(MainActivity.this, String.valueOf(msg.obj),
Toast.LENGTH_SHORT).show();
super.handleMessage(msg);
}
};
// 線程服務(wù)類
private class AcceptThread extends Thread {
private BluetoothServerSocket serverSocket;
private BluetoothSocket socket;
// 輸入 輸出流
private OutputStream os;
private InputStream is;
public AcceptThread() {
try {
serverSocket = mBluetoothAdapter
.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
// 截獲客戶端的藍(lán)牙消息
try {
socket = serverSocket.accept(); // 如果阻塞了犀呼,就會(huì)一直停留在這里
is = socket.getInputStream();
os = socket.getOutputStream();
// 不斷接收請(qǐng)求,如果客戶端沒(méi)有發(fā)送的話還是會(huì)阻塞
while (true) {
// 每次只發(fā)送128個(gè)字節(jié)
byte[] buffer = new byte[128];
// 讀取
int count = is.read();
// 如果讀取到了,我們就發(fā)送剛才的那個(gè)Toast
Message msg = new Message();
msg.obj = new String(buffer, 0, count, "utf-8");
handler.sendMessage(msg);
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
}