手把手教你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了,並且手上也沒有藍牙串中。沒辦法調試了。對不起了各位。







    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM