手把手教你Android手机与BLE终端通信--连接,发送和接收数据

    假设你还没有看上一篇 手把手教你Android手机与BLE终端通信--搜索,你就先看看吧,由于这一篇要接着讲搜索到蓝牙后的连接。和连接后的发送和接收数据。


    评论里有非常多人问假设一条信息特别长,怎么不丢包,或者怎么推断一个完整的信息发送完了呢。

我写的时候连的串口是我们公司硬件project师设计的,他定义好了信息的格式。什么字符开头。什么字符结尾,中间哪几位代表什么意思,我假设不能成功取到一对开头和结尾而且长度也符合我就会丢弃那点信息,取得的完整信息则会依据硬件project师的文档取出app对应地方用到的对应信息。嗯。就是这样。假设你不知道一个串口发给你什么信息,那一定是你拿来玩的串口,工作中用到的都是定制的,不然连接串口干什么呢。

    我的基本实现就是全部蓝牙操作都写在BluetoothController中,他有消息要发送时发送到BLEService中,service再发广播提示MainActivity更新页面。好了,切入正题。。

    1。连接

    首先点击搜索到的蓝牙的listview,连接点击的那个蓝牙:

listview.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?

> arg0, View arg1, int index, long arg3) { BluetoothController.getInstance().connect(list.get(index)); } });

connect方法仍然写在controller中,那个与蓝牙控制类。
/**
	 * 连接蓝牙设备
	 * 
	 * @param device
	 *            待连接的设备
	 */
	public void connect(EntityDevice device) {
		deviceAddress=device.getAddress();
		deviceName=device.getName();
		BluetoothDevice localBluetoothDevice = bleAdapter
				.getRemoteDevice(device.getAddress());
		if (bleGatt != null) {

			bleGatt.disconnect();
			bleGatt.close();
			bleGatt = null;
		}
		bleGatt = localBluetoothDevice.connectGatt(App.app, false,
				bleGattCallback);
	}
bleGatt是与蓝牙沟通的控制类,系统自带的BluetoothGatt类,它能够连接。断开某设备,或者获取服务,写数据。

蓝牙有非常多服务。但我们要找那个可读写的服务,以下会有查找服务。

你应该注意到bleGattCallback。BluetoothGattCallback,也是系统自带的类。是连接回调类,连接后出现什么情况怎么处理就在这里了。它有非常多方法须要重写。我们仅仅重写两三个。关于连接我们须要重写的是onConnectionStateChange(BluetoothGatt paramAnonymousBluetoothGatt, int oldStatus,int newStatus),第一个參数不用管。我也不知道是什么,第二个參数是原来的状态,第三个參数是后来的状态,这本来就是状态改变回调方法嘛。

对了。0表示未连接上,2表示已连接设备。当成功连接后我们要更新界面,未连接也要更新。由于可能是连接过程中意外中断,也可能有意中断,提醒下亲爱的用户还是比較好的。

/**
		 * 连接状态改变
		 */
		public void onConnectionStateChange(
				BluetoothGatt paramAnonymousBluetoothGatt, int oldStatus,
				int newStatus) {
			if (newStatus == 2)// 已连接状态。表明连接成功
			{
				Message msg=new Message();
				msg.what=ConstantUtils.WM_BLE_CONNECTED_STATE_CHANGE;
				Bundle bundle=new Bundle();
				bundle.putString("address", deviceAddress);
				bundle.putString("name", deviceName);
				msg.obj=bundle;
				serviceHandler.sendMessage(msg);
				paramAnonymousBluetoothGatt.discoverServices();
				//连接到蓝牙后查找能够读写的服务。蓝牙有非常多服务
				return;
			}
			if (newStatus == 0)// 断开连接或未连接成功
			{
				serviceHandler.sendEmptyMessage(ConstantUtils.WM_STOP_CONNECT);
				return;
			}
			paramAnonymousBluetoothGatt.disconnect();
			paramAnonymousBluetoothGatt.close();
			return;
		}
这样连接状态改变的消息就发到了service, service接收到消息后发广播提醒界面更新

Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case ConstantUtils.WM_BLE_CONNECTED_STATE_CHANGE:// 连接上某个设备的消息
				Bundle bundle = (Bundle) msg.obj;
				String address = bundle.getString("address");
				String name = bundle.getString("name");
				// 连接状态改变广播
				Bundle bundle1 = new Bundle();
				bundle1.putString("address", address);
				bundle1.putString("name", name);
				Intent intentDevice = new Intent(
						ConstantUtils.ACTION_CONNECTED_ONE_DEVICE);
				intentDevice.putExtras(bundle1);
				sendBroadcast(intentDevice);
				break;

			case ConstantUtils.WM_STOP_CONNECT:
				Intent stopConnect = new Intent(
						ConstantUtils.ACTION_STOP_CONNECT);
				sendBroadcast(stopConnect);
				break;

然后主界面MainActivity接收到广播后更新页面。假设是连接就把连接的设备地址打印出来,假设是断开了,就清除打印而且弹一个toast.当然这些代码在一个receiver中。

else if (intent.getAction().equalsIgnoreCase(ConstantUtils.ACTION_CONNECTED_ONE_DEVICE)){
				connectedDevice.setText("连接的蓝牙是:"+intent.getStringExtra("address"));
			}
			
			else if (intent.getAction().equalsIgnoreCase(ConstantUtils.ACTION_STOP_CONNECT)){
				connectedDevice.setText("");
				toast("连接已断开");
			}
为了測试断开。我关了蓝牙,你能够试试。


2,接收数据

  首先你须要下载一个串口助手。能够看到串口接收到的数据。也能够通过串口发送数据到跟他连接的设备。

  查看接收到的数据仅仅须要重写上面串口回调BluetoothGattCallback的一个方法,public void onCharacteristicChanged(BluetoothGatt paramAnonymousBluetoothGatt,  BluetoothGattCharacteristic paramAnonymousBluetoothGattCharacteristic) 

/**
	 * 与蓝牙通信回调
	 */
	public BluetoothGattCallback bleGattCallback = new BluetoothGattCallback() {
		/**
		 * 收到消息
		 */
		public void onCharacteristicChanged(
				BluetoothGatt paramAnonymousBluetoothGatt,
				BluetoothGattCharacteristic paramAnonymousBluetoothGattCharacteristic) {

			byte[] arrayOfByte = paramAnonymousBluetoothGattCharacteristic
					.getValue();
			if(BluetoothController.this.serviceHandler!=null){
				Message msg=new Message();
				msg.what=ConstantUtils.WM_RECEIVE_MSG_FROM_BLE;
				//byte数组转换为十六进制字符串
				msg.obj=ConvertUtils.getInstance().bytesToHexString(arrayOfByte);
				BluetoothController.this.serviceHandler.sendMessage(msg);
			}
			//也能够先打印出来看看
			Log.i("TEST",ConvertUtils.getInstance().bytesToHexString(arrayOfByte));
		}
接下来的操作还是一样,接受到数据发消息到service,service发广播更新到activity界面。

byteToHexString是把byte数组转化成16进制的数值的字符串。

3,发送数据

在输入框上填入要发送的数据,点button发送数据

btnSend.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				String str=editSend.getText().toString();
				if(str!=null&&str.length()>0){
					controller.write(str.getBytes());
				}
				else {
					toast("请填上要发送的内容");
				}
				
			}
		});
发送方法也在controller中

/**
	 * 数据传输
	 * 
	 * @param byteArray
	 * @return
	 */
	public boolean write(byte byteArray[]) {
		if (bleGattCharacteristic == null)
			return false;
		if (bleGatt == null)
			return false;
		bleGattCharacteristic.setValue(byteArray);
		return bleGatt.writeCharacteristic(bleGattCharacteristic);
	}

	/**
	 * 数据传输
	 * 
	 * @param byteArray
	 * @return
	 */
	public boolean write(String str) {
		if (bleGattCharacteristic == null)
			return false;
		if (bleGatt == null)
			return false;
		bleGattCharacteristic.setValue(str);
		return bleGatt.writeCharacteristic(bleGattCharacteristic);
	}
这里又用来了一个新类,BluetoothGattCharacteristic,他封装了要发送数据。通过bleGatt发送就能够了。bleGatt管的就是连接。断开连接和发送。

最后,一定不要忘了蓝牙的服务,蓝牙有非常多服务,要找到我们要的,你怎么知道要那个服务呢,把每一个服务的属性都打印出来,你就发现仅仅有一个服务的属性是可读可写的。找到它赋值给数据封装类bleGattCharacteristic即可了。

重写回调的onServicesDiscovered(BluetoothGatt paramAnonymousBluetoothGatt, int paramAnonymousInt)方法发现服务。

public void onServicesDiscovered(
				BluetoothGatt paramAnonymousBluetoothGatt, int paramAnonymousInt) {
			BluetoothController.this.findService(paramAnonymousBluetoothGatt
					.getServices());
		}

	/**
	 * 搜索服务
	 * 
	 * @param paramList
	 */
	public void findService(List<BluetoothGattService> paramList) {

		Iterator localIterator1 = paramList.iterator();
		while (localIterator1.hasNext()) {
			BluetoothGattService localBluetoothGattService = (BluetoothGattService) localIterator1
					.next();
			if (localBluetoothGattService.getUuid().toString()
					.equalsIgnoreCase(ConstantUtils.UUID_SERVER)) {
				List localList = localBluetoothGattService.getCharacteristics();
				Iterator localIterator2 = localList.iterator();
				while (localIterator2.hasNext()) {
					BluetoothGattCharacteristic localBluetoothGattCharacteristic = (BluetoothGattCharacteristic) localIterator2
							.next();
					if (localBluetoothGattCharacteristic.getUuid().toString()
							.equalsIgnoreCase(ConstantUtils.UUID_NOTIFY)) {
						bleGattCharacteristic = localBluetoothGattCharacteristic;
						break;
					}
				}
				break;
			}

		}

		bleGatt.setCharacteristicNotification(bleGattCharacteristic, true);
	}

服务号:

public final static  String UUID_SERVER="0000ffe0-0000-1000-8000-00805f9b34fb";
		public final static  String UUID_NOTIFY="0000ffe1-0000-1000-8000-00805f9b34fb";

到哪儿都一样。


假设你看到这儿了,恭喜你,以下都是必备干货:

代码就是这样,包含上次的搜索都在以下的连接里。里面有.apk文件,你先跑跑看效果,还有串口助手exe文件。还有es里的代码,还有串口如何使用,如何配置,我真是太贴心了吐舌头

http://pan.baidu.com/s/1geCKYJL

(不要忘了在manifest中加一个权限,为了兼容6.0以上手机:

<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>

真的非常抱歉,假设看了这篇文章还有什么不懂的我已经解答不了了,我已经不维护这个app了,并且手上也没有蓝牙串中。没办法调试了。对不起了各位。







    

posted @ 2018-04-17 14:58  zhchoutai  阅读(8471)  评论(0编辑  收藏  举报