欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Adroid简单使用蓝牙开发(1)

程序员文章站 2024-03-24 23:14:28
...

Android简单使用蓝牙开发

虽然蓝牙传输速度很慢,但是在手机应用中使用得还是比较广泛的,由于蓝牙使用不需要网络等特点,它在智能家居中使用还是比较广泛的,比如说小区的门禁,很多门禁都会有蓝牙开锁的功能。蓝牙每次数据传输最多传送20个字节,相对其他传输协议,蓝牙传输是很慢的,它需要将许许多多的20个字节拼接成一个完整的包。不多说上下代码吧!推荐博客(https://blog.csdn.net/dingjikerbo/article/category/5889559)

[TOC]

1、先请求搜索蓝牙,获取到蓝牙列表

1.1、搜索蓝牙,设置搜索结果回调对象

private void startSearchBlueDevices() {
		SearchRequest request = new SearchRequest.Builder().searchBluetoothLeDevice(5000, 2).build();
		
		ClientManager.getClient().search(request, mSearchResponse);
		
	}

1.2、回调对象实现代码

	private final SearchResponse mSearchResponse = new SearchResponse() {
		@Override
		public void onSearchStarted() {
			mInfoTextView.setText(R.string.blue_searching);
			
			mDevicesList.clear();
		}
		
		@Override
		public void onDeviceFounded(SearchResult device) {
			if (device != null && !StringUtil.isNull(device.getName())) {
				if (device.getName().startsWith("SN:")) {
					if (!mDevicesList.contains(device)) {
						mDevicesList.add(device);
						mBlueDeviceAdapter.notifyNewData(mDevicesList);
					}
				}
			}
			
		}
		
		@Override
		public void onSearchStopped() {
			mInfoTextView.setText(R.string.blue_device_list);


		}
		
		@Override
		public void onSearchCanceled() {
			mInfoTextView.setText(R.string.blue_device_list);

		}
	};
	

2、有了蓝牙列表就可以设置蓝牙点击事件了

2.1、设置蓝牙列表点击事件,并选择注册对应的蓝牙监听或取消蓝牙监听

@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		switch (parent.getId()) {
			case R.id.blue_device_gridView :
				if (mDevicesList != null && mDevicesList.size() > position) {
					if(!mIsConnected || (mBluetoothDevice != null && !mBluetoothDevice.getAddress().equalsIgnoreCase(mDevicesList.get(position).getAddress()))) {
						if(mIsConnected){
							mIsConnected = false;
							if(mBluetoothDevice != null) {
								ClientManager.getClient().disconnect(mBluetoothDevice.getAddress());
								ClientManager.getClient().unregisterConnectStatusListener(mBluetoothDevice.getAddress(), mConnectStatusListener);
							}
						}

						mBluetoothDevice = BluetoothUtils.getRemoteDevice(mDevicesList.get(position).getAddress());
						if (mBluetoothDevice != null) {
							ClientManager.getClient().registerConnectStatusListener(mBluetoothDevice.getAddress(), mConnectStatusListener);
							connectDeviceIfNeeded();
						}
					}

				}
				break;
			default:
				break;
		}
		
	}

2.2、通过点击蓝牙列表,触发蓝牙通讯并获取(获取蓝牙的mac地址、CharacterUuid、ServiceUuid这些信息是用来蓝牙间进行通讯,传递数据的)

	private void connectDeviceIfNeeded(){
		Log.e(TAG, "enter connectDeviceIfNeeded");
		if (!mIsConnected && !mIsEnterSatelliteActivity) {
			mBluetoothDetailInfo = null;
			showConnectDialog();
			connectDevice();
		}
	}

private void connectDevice() {
		
		BleConnectOptions options = new BleConnectOptions.Builder().setConnectRetry(3).setConnectTimeout(10000).setServiceDiscoverRetry(3)
				.setServiceDiscoverTimeout(10000).build();
		ClientManager.getClient().connect(mBluetoothDevice.getAddress(), options, new BleConnectResponse() {
			@Override
			public void onResponse(int code, BleGattProfile profile) {


				if (code == REQUEST_SUCCESS) {
					mBluetoothDetailInfo = null;
					//mCustomToast.ShowToast(R.string.connect_success);
					if(mHandler != null && profile != null){
						List<BleGattService> services = profile.getServices();

						for (BleGattService service : services) {
							if(Constant.BULETOOTH_SERVICE_UUID.equalsIgnoreCase(service.getUUID().toString())) {
								List<BleGattCharacter> characters = service.getCharacters();
								for (BleGattCharacter character : characters) {
									if(Constant.BULETOOTH_CHARACTER_UUID.equalsIgnoreCase(character.getUuid().toString())){
										mBluetoothDetailInfo = new BluetoothDetailInfo();
										mBluetoothDetailInfo.setBlueName(mBluetoothDevice.getName());
										mBluetoothDetailInfo.setBlueMac(mBluetoothDevice.getAddress());
										mBluetoothDetailInfo.setType(BluetoothDetailInfo.TYPE_CHARACTER);
										mBluetoothDetailInfo.setCharacterUuid(character.getUuid());
										mBluetoothDetailInfo.setServiceUuid(service.getUUID());
										break;
									}
								}
								break;
							}
						}

//						mHandler.sendEmptyMessage(ENTER_SATELLITE_ACTIVITY);

							mHandler.sendEmptyMessage(OPEN_BLUETOOTH_NOTIFY);
					}
				}else{
                    hideConnectDialog();
					mCustomToast.ShowToast(R.string.connect_failed);
				}
			}
		});
	}

3、使用mac地址、serviceUuid、characterUuid来打开蓝牙通讯,并设置接收数据回调对象

3.1、打开蓝牙通讯

private void openNotify() {
		if (StringUtil.isNull(mBluetoothDetailInfo.getBlueMac()) || mBluetoothDetailInfo.getServiceUuid() == null) {
			return;
		}

		ClientManager.getClient().notify(mBluetoothDetailInfo.getBlueMac(),  mBluetoothDetailInfo.getServiceUuid(),  mBluetoothDetailInfo.getCharacterUuid(), mOpenNotifyCallBack);
	}

3.2、接收数据回调对象代码(蓝牙传输带宽有限,每次传输数据最多20字节,最后一次发送不一定满20字节,下面的代码包含如何将数据拼接成一个完整的包)

private final BleNotifyResponse mOpenNotifyCallBack = new BleNotifyResponse() {
		@Override
		public void onNotify(UUID service, UUID character, byte[] data) {
			if (service.equals(mBluetoothDetailInfo.getServiceUuid()) && character.equals(mBluetoothDetailInfo.getCharacterUuid())) {
				String str = ByteUtils.byteToString(data);
				if (str != null) {
					str = str.replaceAll(" ", "");
					str = str.replace("\n", "");
					str = str.replaceAll("\t", "");
					if (!TextUtils.isEmpty(str)) {
						String receiveStr = ByteUtils.byteToString(data);

						if (mReceiveLength <= 0) {
							Log.e(TAG, " str : " + 2);
							getBufferSize(receiveStr);
						}

						if (mReceiveLength > 0 && mReceiveStr.length() <= mReceiveLength - 20) {
							Log.e(TAG, " str : " + 5);
							mReceiveStr += receiveStr;
						} else if (mReceiveLength > 0
								&& (mReceiveStr.length() > mReceiveLength - 20)
								&& mReceiveStr.length() < mReceiveLength) {
							Log.e(TAG, " str : " + 6);
							int end = mReceiveLength - mReceiveStr.length();
							String subStr = receiveStr.substring(0, end);
							mReceiveStr += subStr;
							/**
							 * substring(168,168) == "" not Exception
							 */
							mLastReceiveStr = receiveStr.substring(end, receiveStr.length());

						}

						if (mReceiveLength > 0 && (mReceiveStr.length() == mReceiveLength)) {
							judgeEnterActivity(mReceiveStr);
						}
					}
				}
			}

		}

4、蓝牙的接收数据方法准备好后,再来弄蓝牙发送数据

4.1、蓝牙发送数据每次最多只能发送20字节,因此需要截包

	public static Queue<AppSendDataInfo> splitPacketFor20Byte(byte[] data) {
		Queue<AppSendDataInfo> dataInfoList = new LinkedList<>();
		if (data != null) {
			int index = 0;
			do {
				byte[] surplusData = new byte[data.length - index];
				byte[] currentData;
				System.arraycopy(data, index, surplusData, 0, data.length - index);
				if (surplusData.length <= 20) {
					currentData = new byte[surplusData.length];
					System.arraycopy(surplusData, 0, currentData, 0, surplusData.length);
					index += surplusData.length;
				} else {
					currentData = new byte[20];
					System.arraycopy(data, index, currentData, 0, 20);
					index += 20;
				}
				AppSendDataInfo dataInfo = new AppSendDataInfo();
				dataInfo.setData(currentData);
				dataInfoList.offer(dataInfo);
			} while (index < data.length);
		}
		return dataInfoList;
	}

4.2、包分切完毕后发送

 @Override
    public void run() {
        doService();
    }

    public void doService() {
        try {
            if (mAppSendDataInfoQueue != null && mAppSendDataInfoQueue.size() > 0) {
                mCountDownLatch = new CountDownLatch(mAppSendDataInfoQueue.size());
                long time = System.currentTimeMillis();
                while (mAppSendDataInfoQueue.peek() != null){
                    AppSendDataInfo appSendDataInfo = mAppSendDataInfoQueue.poll();
                    final byte[] sendData = appSendDataInfo.getData();
                    if(appSendDataInfo != null) {
                        cachedThreadPool.execute(new Runnable() {
                            @Override
                            public void run() {
                                // TODO Auto-generated method stub
                                sendPackageToMeter(sendData);
                                mCountDownLatch.countDown();
                            }
                        });
                        Thread.sleep(timeout);
                    }else{
                        mCountDownLatch.countDown();
                    }
                }
                mCountDownLatch.await();
				if (mHandler != null) {
                    Message message = new Message();
					message.obj = time;
					message.what = mMsgWhat;
                    mHandler.sendMessage(message);

				}
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

private void sendPackageToMeter(byte[] data) {
		if (data == null || data.length <= 0) {
			return;
		}
		
		if (StringUtil.isNull(mMacAddr) || mServiceUUid == null) {
			return;
		}
		ClientManager.getClient().write(mMacAddr, mServiceUUid, mCharacterUUid, data, new BleWriteResponse() {
			@Override
			public void onResponse(int code) {
				if (code == REQUEST_SUCCESS) {
					
				}
			}
		});
		
	}

5、当你数据数据传输结束后,不使用蓝牙的时候,需要将其关闭通讯,关闭蓝牙连接

5.1、关闭蓝牙通讯

private void closeNotify() {
		if (StringUtil.isNull(mBluetoothDetailInfo.getBlueMac()) || mBluetoothDetailInfo.getServiceUuid() == null) {
			return;
		}
		ClientManager.getClient().unnotify(mBluetoothDetailInfo.getBlueMac(), mBluetoothDetailInfo.getServiceUuid(),  mBluetoothDetailInfo.getCharacterUuid(), mCloseNotifyCallBack);
	}

5.2、关闭蓝牙连接

	@Override
	protected void onDestroy() {
		super.onDestroy();
		if(mBluetoothDevice != null) {
			ClientManager.getClient().disconnect(mBluetoothDevice.getAddress());
			ClientManager.getClient().unregisterConnectStatusListener(mBluetoothDevice.getAddress(), mConnectStatusListener);
		}

		if(mHandler != null){
			mHandler.removeCallbacksAndMessages(null);
			mHandler = null;
		}
//		closeNotify();
		UpgradeApi.cancelCheckUpgradeRequest();
		UpgradeApi.cancelDownloadApkRequest();


	}

6、总结

6.1、蓝牙连接的大致过程为,首先调用蓝牙少扫描方法,获取到附近的蓝牙列表(重点是蓝牙的mac地址),通过蓝牙的mac地址来进行蓝牙连接,连接后会获得serviceUuid和characterUuid这些东西是用来与蓝牙进行通讯的验证。通讯设置完成后,通过ClientManager.getClient().write方法向另一端写数据,如果另一端有返回数据的话,数据会返回到onNotify回调方法中。最后不需要通讯的时候,关闭通讯ClientManager.getClient().unnotify,关闭蓝牙连接ClientManager.getClient().disconnect。

6.1、这篇文章只是,大致描述怎么怎么简单使用蓝牙通讯,也许我们使用的api不相同,调用的方法也会有所差异。但是蓝牙通讯的大致过程和我上面描述的差不多,希望这篇文章对您有说帮助。如果您想更深入的学习蓝牙推荐博客(https://blog.csdn.net/dingjikerbo/article/category/5889559)

相关标签: Android 蓝牙