标签:
本文章分析了android蓝牙的用法,包括蓝牙的开启关闭、设置可见、开始取消发现、配对、主动连接、反连、广播等。
1、示例演示
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
private BluetoothAdapter bluetoothAdapter;
private static final int ENABLE_BLUETOOTH = 0x0;
private static final int DISCOVER_REQUEST = 0x1;
private List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
ArrayAdapter<String> arrayAdapter;
BluetoothDevice bluetoothDevice;
private BluetoothSocket transferSocket;
/**在收到连接建立的广播后实例化InputStream和OutputStream*/
private OutputStream os;
private InputStream is;
UUID uuid;
EditText inbox;
ListView listView;
byte[] tmpBytes = new byte[32];
public int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
inbox = (EditText) findViewById(R.id.inbox);
listView = (ListView) findViewById(R.id.listView);
listView.setOnItemClickListener(mOnItemClickListener);
arrayAdapter = new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_list_item_1, new ArrayList<String>());
listView.setAdapter(arrayAdapter);
//扁鹊飞救用的UUID号
uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
initBluetooth();
}
private void initBluetooth(){
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(mReceiver, filter);
if(!bluetoothAdapter.isEnabled()){
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), ENABLE_BLUETOOTH);
}else{
startServerSocket();
}
}
@Override
protected void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
unregisterReceiver(mReceiver);
resetSocket();
isRunning = false;
}
/**接收读取的数据,然后发指令*/
private void receiveData(byte[] data, int len) {
System.arraycopy(data, 0, tmpBytes, count, len);
count += len;
if (count == 5 && arrayEquals(tmpBytes, "READY".getBytes(), count)) {// 5 READY
print(tmpBytes, count);
count = 0;
try {
SystemClock.sleep(500);
os.write("VER00".getBytes());// get version data
} catch (IOException e) {
e.printStackTrace();
}
} else if (count == 15 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 14)) {// 1-9-5 receive version data
print(tmpBytes, count);
count = 0;
try {
SystemClock.sleep(500);
os.write("GAT00".getBytes());// get automatic transmission
} catch (IOException e) {
e.printStackTrace();
}
} else if (count == 5 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 4)) {// automatic transmission
byte set = tmpBytes[3];
print(tmpBytes, count);
count = 0;
try {
if (set == 0x00) {//0:not;1:yes若未设置自动传输,就先设置
SystemClock.sleep(500);
os.write(new byte[] { 'S', 'A', 'T', '\0', 0x11, 0x11 });// set automatic transmission
SystemClock.sleep(500);
}
os.write("GPD00".getBytes());// get profile data
} catch (IOException e) {
e.printStackTrace();
}
} else if (count == 14 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 13)) {// 1-8-5 receive profile data
print(tmpBytes, count);
count = 0;
try {
SystemClock.sleep(500);
os.write("GDN00".getBytes());// send 'get data number' command
} catch (IOException e) {
e.printStackTrace();
}
} else if (count == 8 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 7)) {// 1-7 receive data number
print(tmpBytes, count);
count = 0;
try {
SystemClock.sleep(500);
os.write(new byte[] { 'G', 'M', 'D', '\0', 0, 0, 0 });//send 'get measurement data' command
} catch (IOException e) {
e.printStackTrace();
}
} else if (count == 18 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 17)) {// 1-9-8 receive measurement data
print(tmpBytes, count);
count = 0;
try {
SystemClock.sleep(500);
os.write(new byte[]{'T','O','K',(byte) 0xff,(byte) 0xff});
} catch (IOException e) {
e.printStackTrace();
}
}else if(count == 2 && arrayEquals("OK".getBytes(), tmpBytes, count)){//发TOK会收到OK
print(tmpBytes, count);
count = 0;
}
}
/**校验接收到的数据是否正确*/
private boolean checkSum(byte[] data,int start,int end){
byte check = 0;
for(int i=start;i<=end;i++){
check ^= data[i];
}
if(check==0){
return true;
}
return false;
}
/** 判断两个byte数组是否相同
* <li>从两数组0到len位置依次比较 */
private boolean arrayEquals(byte[] one, byte[] another, int len) {
if (one == null || another == null) {
return false;
}
if(len<0||len>one.length||len>another.length){
return false;
}
for (int i = 0; i < len; i++) {
if (one[i] != another[i]) {
return false;
}
}
return true;
}
Handler handler = new Handler();
private void print(byte[] bytes, int len){
final StringBuilder sb = new StringBuilder();
for(int i=0;i<len;i++){
sb.append(bytes[i]).append(",");
}
handler.post(new Runnable() {
@Override
public void run() {
inbox.append(sb+"\n");
}
});
}
private boolean listening;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == ENABLE_BLUETOOTH){
if(resultCode == RESULT_OK){
Toast.makeText(this, "Bluetooth is enabled", Toast.LENGTH_SHORT).show();
}
}else if(requestCode == DISCOVER_REQUEST){
if(resultCode == RESULT_OK){
Toast.makeText(this, "Bluetooth is discoverable", Toast.LENGTH_SHORT).show();
}
}
}
public void onClick(View v){
switch (v.getId()) {
case R.id.discoverable:
//对所有附近设备可见,反连使用
//若蓝牙不可用则提示打开蓝牙
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE), DISCOVER_REQUEST);
break;
case R.id.discover:
if(!bluetoothAdapter.isEnabled()){
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), ENABLE_BLUETOOTH);
}else if(!bluetoothAdapter.isDiscovering()){
//inquiry scan of 12s,followed by a page scan of each new device
bluetoothAdapter.startDiscovery();
}
break;
case R.id.accept:
startServerSocket();
break;
case R.id.clearEdit:
inbox.setText("");
arrayAdapter.clear();
deviceList.clear();
}
}
boolean isRunning = true;
/**
* 当前设备作为server反连,监听连接请求
* 单开线程循环监听连接
*/
private void startServerSocket(){
Toast.makeText(this, "反连过程启动", Toast.LENGTH_SHORT).show();
try {
final BluetoothServerSocket server = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("bluetoothserver", uuid);
new Thread(new Runnable() {
@Override
public void run() {
while(isRunning){
try {
transferSocket = server.accept();
try {
is = transferSocket.getInputStream();
os = transferSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
if(mReadThread==null||!mReadThread.isAlive()){
mReadThread = new ReadThread();
mReadThread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
/**主动连接设备*/
private OnItemClickListener mOnItemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
try {
BluetoothDevice bluetoothDevice = deviceList.get(position);
Log.d(TAG, "before bond-"+bluetoothDevice.getBondState());
if(bluetoothDevice.getBondState()==BluetoothDevice.BOND_BONDING){
Toast.makeText(MainActivity.this, "正在配对...", Toast.LENGTH_SHORT).show();
return;
}
if(bluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE){
// boolean retValue = bluetoothDevice.createBond();//配对or
Method method = BluetoothDevice.class.getMethod("createBond");
boolean retValue = (Boolean) method.invoke(bluetoothDevice);
if(retValue){//true表示配对过程开始
new ConnectThread(true).start();
return;
}
}
new ConnectThread(false).start();
} catch (Exception e) {
e.printStackTrace();
}
}
};
private class ConnectThread extends Thread{
boolean isBonding;
public ConnectThread(boolean isBonding){
this.isBonding = isBonding;
}
@Override
public void run() {
super.run();
if(isBonding){
long start = SystemClock.elapsedRealtime();
while(bluetoothDevice.getBondState()!=BluetoothDevice.BOND_BONDED){
//配对过程大概10s
SystemClock.sleep(50);
}
Log.d(TAG, "配对成功-"+(SystemClock.elapsedRealtime()-start)+"ms");
}
try {
transferSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid);
long start = SystemClock.elapsedRealtime();
transferSocket.connect();//连接
Log.d(TAG, "after connect-"+(SystemClock.elapsedRealtime()-start)+"ms");
is = transferSocket.getInputStream();
os = transferSocket.getOutputStream();
if(mReadThread==null||!mReadThread.isAlive()){
mReadThread = new ReadThread();
mReadThread.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* close InputStream,OutputStream,BluetoothSocket
* 在Activity.onDestroy调用
*/
private void resetSocket(){
Log.d(TAG, "resetSocket");
listening = false;
try {
if(is!=null)
is.close();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
if(os!=null)
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
if(transferSocket!=null)
transferSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())){
Toast.makeText(MainActivity.this, "发现开始", Toast.LENGTH_SHORT).show();
arrayAdapter.clear();
deviceList.clear();
}else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())){
Toast.makeText(MainActivity.this, "发现完成", Toast.LENGTH_SHORT).show();
}else if(BluetoothDevice.ACTION_FOUND.equals(intent.getAction())){
//BluetoothDevice和BluetoothClass均是Parcelable子类
BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
BluetoothClass bluetoothClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
if(remoteDevice!=null&&bluetoothClass!=null){
if(bluetoothClass.getDeviceClass()==BluetoothClass.Device.HEALTH_BLOOD_PRESSURE){
bluetoothDevice = remoteDevice;
deviceList.add(remoteDevice);
arrayAdapter.add(remoteDevice.getName());
bluetoothAdapter.cancelDiscovery();//找到一个符合的设备就停止发现过程
}
}
}else if(BluetoothDevice.ACTION_ACL_CONNECTED.equals(intent.getAction())){
BluetoothDevice currentDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Toast.makeText(MainActivity.this, currentDevice.getName()+" 已连接", Toast.LENGTH_SHORT).show();
}else if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(intent.getAction())){
BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Toast.makeText(MainActivity.this, remoteDevice.getName()+" 已断开", Toast.LENGTH_SHORT).show();
}else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())){
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 0);
if(bondState==BluetoothDevice.BOND_BONDED){
Toast.makeText(MainActivity.this, Build.MODEL+" 绑定成功", Toast.LENGTH_SHORT).show();
}
}
}
};
ReadThread mReadThread;
/**收到设备连上的广播后启动此线程,执行读取远程数据并显示*/
private class ReadThread extends Thread{
@Override
public void run() {
super.run();
try {
byte[] buffer = new byte[32];
int bytesRead = -1;
listening = true;
while(listening){
bytesRead = is.read(buffer);//IOException
if(bytesRead != -1){
receiveData(buffer, bytesRead);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
}<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/discoverable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="设置当前设备可见"
android:onClick="onClick"/>
<Button
android:id="@+id/discover"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="启动发现过程"
android:onClick="onClick"/>
<Button
android:id="@+id/accept"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="启动反连线程"
android:onClick="onClick"/>
<EditText
android:id="@+id/inbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/clearEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="clearEdit"/>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
标签:
原文地址:http://blog.csdn.net/talk2soul/article/details/42834243