标签:
本文章分析了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