日韩性视频-久久久蜜桃-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的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 草草地址线路①屁屁影院成人 | 啪啪av| 天堂中文在线视频 | 看污片网站 | 亚欧美精品 | 日韩精美视频 | 女女h百合无遮涩涩漫画软件 | 国产成人精品在线 | 天天插天天干 | 日本少妇高潮喷水xxxxxxx | 亚洲欧美自拍另类 | 欧美热热 | 热久久久久| 欧美影视 | 久久露脸| 午夜777 | 无人在线观看的免费高清视频 | 午夜精品免费观看 | 特级西西人体4444xxxx | 麻豆影视网站 | 夜色在线影院 | 婷婷色综合 | 日韩国产毛片 | 色老头一区| 欧美日韩你懂的 | 性久久久久久久久久久久 | 极品女神无套呻吟啪啪 | 名人明星三级videos | 在线观看黄色免费视频 | yy6080午夜| 国产乱淫av公 | 国产一区二区三区乱码 | 三年中文在线观看中文版 | 精品久久久久久无码中文野结衣 | 蜜桃91麻豆精品一二三区 | 日本欧美一本 | 神马午夜dy888| 日韩在线中文字幕视频 | 天天操夜夜欢 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产精品男同 | 一本色道久久hezyo加勒比 | 久久久久久免费观看 | 激情视频区 | xvideos永久免费入口 | 久久爱影视i | 色婷婷一区 | 亚洲性色av | 国产玖玖在线 | 国产黑丝91 | 亚洲国产精品无码观看久久 | 美女脱了裤子让男人捅 | 国产欧美日韩精品一区二区三区 | av日韩高清 | 成人国产视频在线观看 | 操女人的逼逼 | 99久久综合国产精品二区 | 日韩欧美高清片 | 欧美午夜精品一区 | 日韩激情| 成人午夜免费视频 | 欧美区视频 | 亚洲视频天堂 | 午夜久久久久久久 | 国产精品无码久久久久成人app | 激情五月色综合国产精品 | 99视频+国产日韩欧美 | 亚洲自拍偷拍网 | 欧美美女一区二区 | 欧美精品在线视频 | 国产猛男猛女超爽免费视频 | 污污污污污污www网站免费 | 蜜臀久久精品久久久久久酒店 | 亚洲一区欧美二区 | 久操热| 永久免费看mv网站入口亚洲 | 超碰98在线观看 | 成人网免费看 | 操亚洲| 亚洲天天看 | xxxxwwww国产 | 狠狠干老司机 | 疯狂做爰的爽文多肉小说王爷 | 看毛片的网址 | 日本人妻丰满熟妇久久久久久 | 曰批免费视频播放免费 | 无码人妻一区二区三区免费n鬼沢 | 99re这里只有精品首页 | 国产精品50页| 久久蜜臀精品av | 成人香蕉视频在线观看 | 色小说在线观看 | 亚洲午夜无码久久久久 | 韩国午夜av| 99热这里只有精品4 精品国产黄色 | 在线免费观看黄色 | 操操综合网| 亚洲国产免费av | 欧美一区二区三区 |