日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android ble蓝牙接收不到数据_Android蓝牙4.0 Ble读写数据详解 -2

發布時間:2025/3/12 Android 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android ble蓝牙接收不到数据_Android蓝牙4.0 Ble读写数据详解 -2 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android藍牙4.0 Ble讀寫數據詳解 -2

上一篇說了如何掃描與鏈接藍牙 這篇文章講講與藍牙的數據傳輸,與一些踩到的坑。

先介紹一款調試工具,專門調試Ble藍牙的app。名字叫:nRF-Connect 谷歌應用商店也能下載到。

這里我先連接一個藍牙設備 貼幾個截圖。

UUID的話 就相當于鑰匙,藍牙設備當中有通道,那么通道是需要UUID進行匹配的

當連接上設備之后,可以看到UUID的通道 接下來,按照設備廠商提供的文檔,找到我們需要的UUID通道

比如說我這里需要的是0x6a的Service通道 然后點開最后一個Service通道查看

展開Service后 可以看到有兩個Characteristic通道

我們看Properties屬性 一個是NOTIFY 一個是WRITE 也有可能會有READ這個屬性的通道

可以拿這個app輸出寫出指令給藍牙,在不清楚是藍牙的問題還是自己的問題的時候,這個工具還是挺好使的。

Notify的話,需要注意這個Descriptors的UUID 這個在注冊Notify的時候,需要用到,這里雖然看不全,但是之后可以通過打印得到。

簡單說一下這三種屬性的通道的用途

WRITE:顧名思義,寫的意思,該通道是用來向藍牙設備寫出數據的通道

READ:向藍牙設備進行讀取數據的通道 這個通道有一個坑 后續會詳細寫上

Notify:該通道需要注冊監聽,這是一個通知的通道,藍牙向你傳輸數據的話,就能直接收到監聽。

我這邊的話 因為一些原因,所以沒有使用READ通道獲取數據 只用了Notify通道 當然 也會講講怎么使用READ

準備工作

先將UUID管理起來,我這里的話 采用靜態常量的形式保存起來了。

public class UUIDManager {

/**

* 服務的UUID

*/

public static final String SERVICE_UUID = "00006a00-0000-1000-8000-00805f9b34fb";

/**

* 訂閱通知的UUID

*/

public static final String NOTIFY_UUID = "00006a02-0000-1000-8000-00805f9b34fb";

/**

* 寫出數據的UUID

*/

public static final String WRITE_UUID = "00006a02-0000-1000-8000-00805f9b34fb";

/**

* NOTIFY里面的Descriptor UUID

*/

public static final String NOTIFY_DESCRIPTOR = "00002902-0000-1000-8000-00805f9b34fb";

}

處理通知回調接口

藍牙的數據回調,其實并不是回調到主線程當中,所以如果接收到數據之后,就進行視圖操作的話,是會失敗的。

所以我打算切換到主線程進行回調,當然,也可以使用EventBus,不過我不喜歡這東西就沒去用。

回調接口的話,打算使用list集合存儲起來,然后回調到各個需要數據的地方。 創建以下三個類

/**

* Created by Pencilso on 2017/4/20.

* 藍牙數據回調監聽接口

*/

public interface BlueNotifyListener {

public void onNotify(Message notify);

}

/**

* Created by Pencilso on 2017/4/25.

* 處理回調所有接口

*/

public class NotifyThread implements Runnable {

private List listeners;

private Message notify;

@Override

public void run() {

if (notify == null || listeners==null)

return;

try {

Iterator iterator = listeners.iterator();

while (iterator.hasNext()) {

BlueNotifyListener next = iterator.next();

if (next == null)

iterator.remove();

else

next.onNotify(notify);

}

} catch (Exception e) {

e.printStackTrace();

}

}

public void setListeners(List listeners) {

this.listeners = listeners;

}

public void setNotify(Message notify) {

this.notify = notify;

}

}

/**

* Created by Pencilso on 2017/4/26.

* 藍牙的Code類 用來自定義回調的標識

*/

public class BlueCodeUtils {

/**

* 藍牙狀態 已連接

*/

public static final int BLUETOOTH_STATE_CONNECT = 0x1;

/**

* 藍牙狀態 已斷開

*/

public static final int BLUETOOTH_STATE_DISCONNECT = 0x2;

//*******這些只是自定義的code 就不復制太多了

}

編寫藍牙的功能

新建BluetoothBinder類 繼承自BluetoothGattCallback

然后把藍牙的功能模塊寫在這里面。

主要的功能都在這個類里面,我把這個放到了服務里面,所以在創建BluetoothBinder的時候需要傳遞一個Service對象

import android.annotation.SuppressLint;

import android.bluetooth.BluetoothAdapter;

import android.bluetooth.BluetoothDevice;

import android.bluetooth.BluetoothGatt;

import android.bluetooth.BluetoothGattCallback;

import android.bluetooth.BluetoothGattCharacteristic;

import android.bluetooth.BluetoothGattDescriptor;

import android.bluetooth.BluetoothGattService;

import android.bluetooth.BluetoothManager;

import android.bluetooth.BluetoothProfile;

import android.content.Context;

import android.os.Build;

import android.os.Message;

import android.support.annotation.RequiresApi;

import android.util.Log;

import java.util.List;

import java.util.UUID;

import cc.petnet.trenmotion.Interface.IBluetoothInterface;

import cc.petnet.trenmotion.utils.HandleUtils;

import cc.petnet.trenmotion.utils.LogUtils;

/**

* Created by Pencilso on 2017/4/20.

* 藍牙操作的Binder

*/

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)

public class BluetoothBinder extends BluetoothGattCallback implements IBluetoothInterface {

private static BluetoothBinder bluetoothBinder;

private final Service bluetoothService;//service服務

private final BluetoothAdapter adapter;//藍牙的適配器

private List notifyList;//監聽的集合

private BluetoothManager bluetoothManager;//藍牙管理者

private BluetoothGattService gattService;//通道服務

private BluetoothGatt bluetoothGatt;

public static IBluetoothInterface getInstace() {

return bluetoothBinder;

}

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)

protected BluetoothBinder(BluetoothService bluetoothService) {

bluetoothBinder = this;

this.bluetoothService = bluetoothService;

bluetoothManager = (BluetoothManager) bluetoothService.getSystemService(Context.BLUETOOTH_SERVICE);

adapter = bluetoothManager.getAdapter();

}

@Override

public void onDestroy() {

bluetoothBinder = null;

}

@Override

public void addNotifyListener(T notifyListener) {

if (notifyListener != null)

notifyList.add(notifyListener);

}

@Override

public void removeNotifyListener(BlueNotifyListener notifyListener) {

if (notifyListener != null)

notifyList.remove(notifyListener);

}

/**

* 廣播藍牙監聽消息

* 因為藍牙發送過來的消息 并不是處于主線程當中的

* 所以如果直接對藍牙的數據展示視圖的話 會展示不了的 這里的話 封裝到主線程當中遍歷回調數據

*

* @param notify

*/

public void traverseListener(Message notify) {

NotifyThread notifyThread = new NotifyThread();//創建一個遍歷線程

notifyThread.setListeners(notifyList);

notifyThread.setNotify(notify);

HandleUtils.getInstace().post(notifyThread);

}

/**

* 系統的藍牙是否已經打開

*

* @return

*/

@Override

public boolean isEnable() {

return adapter.isEnabled();

}

@Override

public void enableBluetooth(boolean enable) {

if (enable)

adapter.enable();

else

adapter.disable();

}

@SuppressWarnings("deprecation")

@SuppressLint("NewApi")

@Override

public void startScanner(BluetoothAdapter.LeScanCallback callback) {

adapter.startLeScan(callback);

}

@SuppressLint("NewApi")

@SuppressWarnings("deprecation")

@Override

public void stopScanner(BluetoothAdapter.LeScanCallback callback) {

adapter.stopLeScan(callback);

}

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)

@Override

public void connectDevices(String address) {

BluetoothDevice remoteDevice = adapter.getRemoteDevice(address);

BluetoothGatt bluetoothGatt = remoteDevice.connectGatt(bluetoothService, false, this);

}

/**

* 藍牙設備狀態的監聽

*

* @param gatt

* @param status

* @param newState 藍牙的狀態被改變

*/

@Override

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

super.onConnectionStateChange(gatt, status, newState);

Message message = new Message();

switch (newState) {//對藍牙反饋的狀態進行判斷

case BluetoothProfile.STATE_CONNECTED://已鏈接

message.what = BlueCodeUtils.BLUETOOTH_STATE_CONNECT;

gatt.discoverServices();

break;

case BluetoothProfile.STATE_DISCONNECTED://已斷開

message.what = BlueCodeUtils.BLUETOOTH_STATE_DISCONNECT;

break;

}

traverseListener(message);

/**

* 這里還有一個需要注意的,比如說藍牙設備上有一些通道是一些參數之類的信息,比如最常見的版本號。

* 一般這種情況 版本號都是定死在某一個通道上,直接讀取,也不需要發送指令的。

* 如果遇到這種情況,一定要在發現服務之后 再去讀取這種數據 不要一連接成功就去獲取

*/

}

/**

* 發現服務

*

* @param gatt

* @param status

*/

@Override

public void onServicesDiscovered(BluetoothGatt gatt, int status) {

super.onServicesDiscovered(gatt, status);

gattService = gatt.getService(UUID.fromString(UUIDManager.SERVICE_UUID));// 獲取到服務的通道

bluetoothGatt = gatt;

//獲取到Notify的Characteristic通道 這個根據協議來定 如果設備廠家給的協議不是Notify的話 就不用做以下操作了

BluetoothGattCharacteristic notifyCharacteristic = gattService.getCharacteristic(UUID.fromString(UUIDManager.NOTIFY_UUID));

BluetoothUtils.enableNotification(gatt, true, notifyCharacteristic);//注冊Notify通知

}

/**

* 向藍牙寫入數據

*

* @param data

*/

@SuppressLint("NewApi")

@Override

public boolean writeBuletoothData(String data) {

if (bluetoothService == null) {

return false;

}

BluetoothGattCharacteristic writeCharact = gattService.getCharacteristic(UUID.fromString(UUIDManager.WRITE_UUID));

bluetoothGatt.setCharacteristicNotification(writeCharact, true); // 設置監聽

// 當數據傳遞到藍牙之后

// 會回調BluetoothGattCallback里面的write方法

writeCharact.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);

// 將需要傳遞的數據 打碎成16進制

writeCharact.setValue(BluetoothUtils.getHexBytes(data));

return bluetoothGatt.writeCharacteristic(writeCharact);

}

/**

* 藍牙Notify推送過來的數據

*

* @param gatt

* @param characteristic

*/

@Override

public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {

super.onCharacteristicChanged(gatt, characteristic);

//如果推送的是十六進制的數據的寫法

String data = BluetoothUtils.bytesToHexString(characteristic.getValue()); // 將字節轉化為String字符串

Message message = new Message();

message.what = BlueCodeUtils.BLUETOOTH_PUSH_MESSAGE;

message.obj = data;

traverseListener(message);//回調數據

// String data = characteristic.getStringValue(0); // 使用場景 例如某個通道里面靜態的定死了某一個值,就用這種寫法獲取 直接獲取到String類型的數據

}

/**

* 這里有一個坑 一定要注意,如果設備返回數據用的不是Notify的話 一定要注意這個問題

* 這個方法是 向藍牙設備寫出數據成功之后回調的方法,寫出成功之后干嘛呢? 主動去藍牙獲取數據,沒錯,自己主動去READ通道獲取藍牙數據

* 如果用的是Notify的話 不用理會該方法 寫出到藍牙之后 等待Notify的監聽 即onCharacteristicChanged方法回調。

*

* @param gatt

* @param characteristic

* @param status

*/

@Override

public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

super.onCharacteristicWrite(gatt, characteristic, status);

if (status == BluetoothGatt.GATT_SUCCESS) { //寫出成功 接下來 該去讀取藍牙設備的數據了

//這里的READUUID 應該是READ通道的UUID 不過我這邊的設備沒有用到READ通道 所以我這里就注釋了 具體使用 視情況而定

// BluetoothGattCharacteristic readCharact = gattService.getCharacteristic(UUID.fromString(READUUID));

// gatt.readCharacteristic(readCharact);

}

}

/**

* 調用讀取READ通道后返回的數據回調

* 比如說 在onCharacteristicWrite里面調用 gatt.readCharacteristic(readCharact);之后 會回調該方法

*

* @param gatt

* @param characteristic

* @param status

*/

@Override

public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

super.onCharacteristicRead(gatt, characteristic, status);

//如果推送的是十六進制的數據的寫法

String data = BluetoothUtils.bytesToHexString(characteristic.getValue()); // 將字節轉化為String字符串

Message message = new Message();

message.what = BlueCodeUtils.BLUETOOTH_PUSH_MESSAGE;

message.obj = data;

traverseListener(message);//回調數據

// String data = characteristic.getStringValue(0); // 使用場景 例如某個通道里面靜態的定死了某一個值,就用這種寫法獲取 直接獲取到String類型的數據

}

}

其實這個BluetoothBinder還定義了一個接口IBluetoothInterface,然后讓BluetoothBinder實現,并且將BluetoothBinder設置單利,暴露方法,提供返回IBluetoothInterface對象

import android.bluetooth.BluetoothAdapter;

import cc.petnet.trenmotion.service.bluetooth.BlueNotifyListener;

/**

* Created by Pencilso on 2017/4/20.

*/

public interface IBluetoothInterface {

/**

*

* @param notifyListener 添加監聽事件

* @param BlueNotifyListener監聽回調接口

*/

void addNotifyListener(T notifyListener);

/**

*

* @param notifyListener 刪除監聽接口

*/

void removeNotifyListener(BlueNotifyListener notifyListener);

/**

* 系統是否開啟了藍牙

*

* @return

*/

boolean isEnable();

/**

* 打開或者關閉系統藍牙

*

* @param enable

*/

void enableBluetooth(boolean enable);

/**

* 啟動掃描

*

* @param callback

*/

void startScanner(BluetoothAdapter.LeScanCallback callback);

/**

* 停止掃描

*

* @param callback

*/

void stopScanner(BluetoothAdapter.LeScanCallback callback);

void onDestroy();

/**

* 連接設備

*

* @param address

*/

void connectDevices(String address);

/**

* 向藍牙寫出數據

* @param data

* @return

*/

public boolean writeBuletoothData(String data);

}

Handler工具 主要用來切換到主線程當中

public class HandleUtils {

private static Handler handler = null;

public static Handler getInstace() {

if (handler == null)

handler = new Handler();

return handler;

}

}

BluetoothUtils

public class BluetoothUtils {

/**

* 是否開啟藍牙的通知

*

* @param enable

* @param characteristic

* @return

*/

@SuppressLint("NewApi")

public static boolean enableNotification(BluetoothGatt bluetoothGatt, boolean enable, BluetoothGattCharacteristic characteristic) {

if (bluetoothGatt == null || characteristic == null) {

return false;

}

if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable)) {

return false;

}

//獲取到Notify當中的Descriptor通道 然后再進行注冊

BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString(UUIDManager.NOTIFY_DESCRIPTOR));

if (clientConfig == null) {

return false;

}

if (enable) {

clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);

} else {

clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);

}

return bluetoothGatt.writeDescriptor(clientConfig);

}

/**

* 將字節 轉換為字符串

*

* @param src 需要轉換的字節數組

* @return 返回轉換完之后的數據

*/

public static String bytesToHexString(byte[] src) {

StringBuilder stringBuilder = new StringBuilder("");

if (src == null || src.length <= 0) {

return null;

}

for (int i = 0; i < src.length; i++) {

int v = src[i] & 0xFF;

String hv = Integer.toHexString(v);

if (hv.length() < 2) {

stringBuilder.append(0);

}

stringBuilder.append(hv);

}

return stringBuilder.toString();

}

/**

* 將字符串轉化為16進制的字節

*

* @param message

* 需要被轉換的字符

* @return

*/

public static byte[] getHexBytes(String message) {

int len = message.length() / 2;

char[] chars = message.toCharArray();

String[] hexStr = new String[len];

byte[] bytes = new byte[len];

for (int i = 0, j = 0; j < len; i += 2, j++) {

hexStr[j] = "" + chars[i] + chars[i + 1];

bytes[j] = (byte) Integer.parseInt(hexStr[j], 16);

}

return bytes;

}

}

藍牙基本上到這已經結束了。

總結

以上是生活随笔為你收集整理的android ble蓝牙接收不到数据_Android蓝牙4.0 Ble读写数据详解 -2的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩影视一区二区三区 | 91在线观看视频 | 欧美午夜一区二区 | 国产成人亚洲综合a∨婷婷 台湾a级片 | 日色网站 | 亚洲成人国产精品 | 日韩一区免费 | 牛av在线| av中文网 | 欧美日韩二三区 | 欧美人成在线视频 | 亚洲精品图区 | 深夜福利一区二区三区 | 天天躁日日躁狠狠躁欧美 | 影音先锋中文字幕在线播放 | 午夜在线不卡 | 嫩草精品 | 香蕉视频在线免费 | 国产精品永久 | 中国性老太hd大全69 | 免费一级黄 | 日韩欧美成人一区二区三区 | 在线国产欧美 | 欧美极品少妇xxxxⅹ喷水 | 成人高清在线 | 国产日产亚洲系列最新 | 日韩专区欧美专区 | 99在线免费观看 | av网站一区二区 | 女futa攻玩遍整个后宫 | 五月天久久综合 | 波多野结衣在线一区二区 | 中国色视频 | 校园春色亚洲色图 | 丝袜一级片| 国产丝袜美腿一区二区三区 | 久久精品国产亚洲av麻豆色欲 | 女生脱裤子让男生捅 | 国产精品8 | 日韩男女啪啪 | 2018自拍偷拍 | 伊人网综合网 | 天堂av最新网址 | 国产精品久久久久久久久免费相片 | 久久精品无码Av中文字幕 | 国产一区二区在线观看视频 | 天堂一区二区三区 | 日韩女优在线视频 | 另类综合在线 | 污污网站在线免费观看 | 国内性视频 | www.狠狠撸.com | 人人干人人插 | 丁香六月五月婷婷 | 波多野结衣中文字幕一区二区 | 久久精品69 | 丁香激情婷婷 | 天堂а√在线最新版中文在线 | 久久久蜜桃一区二区 | 午夜免费视频网站 | 国产伦一区二区三区 | 久久伊人一区 | 麻豆人妻少妇精品无码专区 | 午夜视频免费在线 | 伊人黄网 | 国产伦精品一区二区三 | 欧洲一区二区在线 | 富二代成人短视频 | 日韩国产精品一区二区 | 韩国三级hd中文字幕 | 亚洲欧美综合精品久久成人 | 国产情侣av自拍 | 午夜久久视频 | 三级av网址 | 国产嫩草影院久久久 | 131mm少妇做爰视频 | 在线观看av网页 | 少妇高潮毛片色欲ava片 | av福利在线免费观看 | 欧美大片一区二区 | 男男gay同性三级 | avwww.| 国产黄色av片 | 丝袜福利视频 | re久久| 强迫凌虐淫辱の牝奴在线观看 | 顶级毛茸茸aaahd极品 | 麻豆av一区二区三区在线观看 | 国产精品久久久久9999 | 一级性视频 | 日韩欧美一区二区三区在线 | 亚洲精品久久久久久国产精华液 | 国产豆花视频 | 麻豆精品在线播放 | 三上悠亚在线一区二区 | 男人午夜影院 | 国产99色 | 久久艹在线视频 | 日本少妇激三级做爰在线 |