Я много рассказывал о Bluetooth с низким энергопотреблением в Android, но не рассказывал об этом аспекте Harmony. На самом деле я работал над проектом Harmony BLE, поэтому поделюсь здесь некоторым контентом.
Разработка Bluetooth для Ble в Harmony на самом деле аналогична разработке в Android, но есть некоторые различия, поскольку SDK Harmony все еще совершенствуется. Здесь мы используем API 6 для разработки проектов, а используемый язык — Java. Что касается того, почему мы используем API 6 вместо последней версии API 9, потому что я не могу позволить себе быть далеко впереди, поэтому я могу использовать только HUAWEI P30. с API 6 для реальных испытаний машин. Такие приложения, как Bluetooth, необходимо тестировать на реальной машине. Использовать виртуальную машину нельзя. Без лишних слов, давайте начнем.
Приступаем к созданию проекта.
выбиратьEmpty Ability
,НажмитеNext。Мы создаем файл с именемHarmonyBle
Проект,Язык — Java.
НажмитеFinish
Завершить создание。
Проект по умолчанию выглядит так. Очень ли он похож на проект, созданный Android?
Гармония также имеет концепцию Разрешения.,Также необходимо Конфигурациястатический Разрешенияи динамика Разрешения,только Конфигурациястатический Разрешенияместа разные。Harmonyнаходится вconfig.json
середина,Код внутри выглядит следующим образом:
{
"app": {
"bundleName": "com.llw.ble",
"vendor": "example",
"version": {
"code": 1000000,
"name": "1.0.0"
}
},
"deviceConfig": {
},
"module": {
"package": "com.llw.ble",
"name": ".MyApplication",
"mainAbility": "com.llw.ble.MainAbility",
"deviceType": [
"phone",
"tablet",
"tv",
"wearable",
"car"
],
"distro": {
"deliveryWithInstall": true,
"moduleName": "entry",
"moduleType": "entry",
"installationFree": false
},
"abilities": [
{
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
],
"name": "com.llw.ble.MainAbility",
"description": "$string:mainability_description",
"icon": "$media:icon",
"label": "$string:entry_MainAbility",
"launchType": "standard",
"orientation": "unspecified",
"visible": true,
"type": "page"
}
]
}
}
Вы это прочитали,ты найдешь,Это иAndroidизAndroidManifest.xml
Конфигурация Файлы вроде одинаковые。только一个用из是json,Один использует xml.
так что мы Конфигурация Разрешения也находится вconfig.json
середина,Например, при сканировании Bluetooth нам нужно найти Разрешения. Вы можете добавить внутрь следующий код:
"reqPermissions": [
{
"name": "ohos.permission.LOCATION"
},
{
"name": "ohos.permission.USE_BLUETOOTH"
},
{
"name": "ohos.permission.DISCOVER_BLUETOOTH"
},
{
"name": "ohos.permission.MANAGE_BLUETOOTH"
}
]
Как показано на рисунке ниже, обратите внимание на знаки препинания в json.
Затем нам следует написать код, но перед этим мы сначала поймем разницу между «Ability» и «Slice». Способность похожа на рамку для изображения, а Slice — на холст. Мы можем загружать несколько холстов в кадр, как при переходе между несколькими страницами. Затем мы добавляем отсканированный фрагмент. Копируем MainAbilitySlice и вставляем его снова. Появляется всплывающее окно «Изменить имя».
Почему нам нужно создавать файлы Java таким способом? Поскольку я не могу создавать файлы Java в DevEco Studio, возможно, в этой версии DS нет этой опции или я ее не нашел.
Далее нам нужно создать соответствующий файл макета, а затем создать срез_scan.xml в разделе resources/base/layout. Код выглядит следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<ListContainer
ohos:id="$+id:lc_device"
ohos:height="match_parent"
ohos:width="match_parent"/>
</DirectionalLayout>
Затем мы модифицируем содержимое ScanSlice и позволяем ему загрузить файл среза_scan.xml, который мы только что написали. Измените метод onStart(), код выглядит следующим образом:
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_slice_scan);
}
Теперь приложение будет запускать MainAbility по умолчанию после его открытия. Давайте посмотрим на это.
public class MainAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilitySlice.class.getName());
}
}
можно увидеть,В методе setMainRoute(),默认加载из是MainAbilitySlice
,将它改为我们刚写好изScanSlice
,код:super.setMainRoute(ScanSlice.class.getName());
Тогда давайте сначала запустим его и подключим к телефону Hongmeng через USB.
Здесь появится сообщение об ошибке. Просмотрите сообщение об ошибке.
Это значит, что нам нужно КонфигурацияSigning。НажмитеRunподили者右侧弹窗изOpen signing configs
,Откроется окно Конфигурация.,Как показано ниже:
我们НажмитеSigning Configs
Параметры,Требуется войти в систему,Как показано ниже:
Здесь вам необходимо войти в свою учетную запись Huawei. В настоящее время мы работаем локально, поэтому рядом с ним находится релиз, чтобы указать версию выпуска. Конфигурации в нем такие же, как и в режиме отладки. Разница в том, что информацию о конфигурации в режиме отладки необходимо вводить только после входа в систему. Studio поможет нам автоматически сгенерировать его, тогда как информация в Release требует, чтобы разработчики зашли на официальный сайт разработчика Huawei, чтобы создать приложение и подать заявку на файл конфигурации и сертификат. Это более хлопотно, но если вы хотите разместить приложение. полке, вы должны сделать этот шаг. В Китае рынок приложений Huawei является самым строгим, когда дело доходит до листинга приложений. С Huawei можно справиться, но остальные просто несерьезны и не заслуживают упоминания.
Давайте сначала войдем в систему, и откроется веб-страница. После успешного входа вы увидите вот такую страницу.
Затем возвращаемся в DS и сертификат и файл конфигурации в режиме Debug будут автоматически настроены, как показано на рисунке ниже:
Нажмите ОК.,Сделаю конфигурацию в DS.,Конфигурация好之后你可以существовать工程目录下изbuild.gradle
середина看到debugиз相关信息,Как показано ниже.
Тогда давайте запустим его еще раз и посмотрим. На этот раз нет никаких сомнений в том, что он может работать успешно. Как показано ниже:
可以看到默认из标题栏Точно так же, какAndroid
默认изActionBar
,Уродливый очень особенный,давай удалим это,Добавьте следующий код в config.json:
"metaData": {
"customizeData": [
{
"extra": "",
"name": "hwc-theme",
"value": "androidhwext:style/Theme.Emui.Light.NoTitleBar"
}
]
},
Добавьте местоположение следующим образом:
Давайте запустим его еще раз и посмотрим.
Да или нетUnbelievable!
И ради красивого названия,мыelementСоздайте его подcolor.json
,Код внутри выглядит следующим образом:
{
"color": [
{
"name": "white",
"value": "#FFF"
},
{
"name": "black",
"value": "#000"
},
{
"name": "blue",
"value": "#FFA7D3FF"
},
{
"name": "bg_color",
"value": "#F8F8F8"
},
{
"name": "gray",
"value": "#989898"
}
]
}
Давайте изменим код в scan_slice.xml следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:background_element="$color:bg_color"
ohos:orientation="vertical">
<DirectionalLayout
ohos:height="50vp"
ohos:width="match_parent"
ohos:alignment="vertical_center"
ohos:background_element="$color:blue"
ohos:orientation="horizontal"
ohos:start_padding="12vp">
<Text
ohos:id="$+id:title"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="Выбрать устройство"
ohos:text_color="#FFF"
ohos:text_font="HwChinese-medium"
ohos:text_size="18fp"
ohos:weight="1"/>
<Text
ohos:id="$+id:tx_scan_status"
ohos:height="match_content"
ohos:width="match_content"
ohos:end_margin="6vp"
ohos:padding="8vp"
ohos:text="Поиск"
ohos:text_color="#FFF"
ohos:text_size="14fp"/>
</DirectionalLayout>
<ListContainer
ohos:id="$+id:lc_device"
ohos:height="match_parent"
ohos:width="match_parent"/>
</DirectionalLayout>
этотDirectionalLayout
Планировка представляет собой линейную планировку.,我们可以Нажмите右侧导航栏изPreviewer
Предварительный просмотр макета,Как показано ниже.
Нажмите значок T в правом верхнем углу, чтобы просмотреть текущий уровень макета.
Позвольте мне объяснить здесь,Иногда значение цвета не действует при использовании его через ресурсы.,Таким образом, он будет использоваться напрямую#FFF
,То же самое верно и в коде,Это должна быть ошибка компилятора.
Строка заголовка написана, а строку состояния мы не изменили. Мы изменили строку состояния в MainAbility. Код выглядит следующим образом:
@Override
public void onStart(Intent intent) {
Window window = WindowManager.getInstance().getTopWindow().get();
window.setStatusBarColor(Color.getIntColor("#A7D3FF"));
super.onStart(intent);
super.setMainRoute(ScanSlice.class.getName());
}
Или изменитьonStart()
метод,Тогда давайте запустим и посмотрим.
Хорошо, давайте напишем код контента, необходимый для сканирования.
首先мыcom.llw.ble
Создать новый под пакетомcore
Сумка,core
Сумка Создайте его подBleCore
добрый,Здесь есть все, что связано с управлением BleBluetooth.,Например, сканирование,соединять,Такие операции, как чтение и запись данных.,我们先不写код。подсуществоватьcore
Сумка Создайте его подscan
Сумка。
scan
Создать новый под пакетомScanCallback
интерфейс,Код выглядит следующим образом:
public interface ScanCallback {
void onScanResult(BleScanResult result);
default void onGroupScanResultsEvent(List<BleScanResult> results){}
default void onScanFailed(String failed){}
}
затем вscan
Создать новый под пакетомBleScanдобрый,Код выглядит следующим образом:
public class BleScan {
private final BleCentralManager centralManager;
private boolean isScanning = false;
private ScanCallback scanCallback;
// Создайте фильтры сканирования и начните сканирование
private List<BleScanFilter> filters;
private static volatile BleScan mInstance;
//инициализация
public static BleScan getInstance(Context context) {
if (mInstance == null) {
synchronized (BleScan.class) {
if (mInstance == null) {
mInstance = new BleScan(context);
}
}
}
return mInstance;
}
public BleScan(Context context) {
BleScanCallback centralManagerCallback = new BleScanCallback();
centralManager = new BleCentralManager(context, centralManagerCallback);
}
/**
* Сканирует ли он сейчас?
* @return true Сканирование, ложь Не сканируется
*/
public boolean isScanning() {
return isScanning;
}
/**
* Установить информацию о фильтре
* @param filters Список фильтров сканирования Bluetooth
*/
public void setFilters(List<BleScanFilter> filters) {
this.filters = filters;
}
/**
* Установите обратный вызов сканирования. Страница должна быть реализована для получения сканируемого устройства.
* @param scanCallback Сканировать обратный вызов
*/
public void setScanCallback(ScanCallback scanCallback) {
this.scanCallback = scanCallback;
}
/**
* Начать сканирование
*/
public void startScan() {
if (centralManager == null) {
localScanFailed("Bluetooth not turned on.");
return;
}
centralManager.startScan(filters);
isScanning = true;
}
/**
* Остановить сканирование
*/
public void stopScan() {
if (!isScanning) {
localScanFailed("Not currently scanning, your stop has no effect.");
return;
}
centralManager.stopScan();
isScanning = false;
}
/**
* 实现Сканировать обратный вызов
*/
public class BleScanCallback implements BleCentralManagerCallback {
@Override
public void scanResultEvent(BleScanResult bleScanResult) {
if (scanCallback != null) {
scanCallback.onScanResult(bleScanResult);
}
}
@Override
public void scanFailedEvent(int resultCode) {
if (scanCallback != null) {
scanCallback.onScanFailed(String.valueOf(resultCode));
}
}
@Override
public void groupScanResultsEvent(final List<BleScanResult> scanResults) {
// Результаты сканирования обработки
if (scanCallback != null) {
scanCallback.onGroupScanResultsEvent(scanResults);
}
}
}
/**
* Обработка ошибок локального сканирования
* @param failed сообщение об ошибке
*/
private void localScanFailed(String failed) {
if (scanCallback != null) {
scanCallback.onScanFailed(failed);
}
}
}
При этом используется одноэлементный режим, который вызывается непосредственно после инициализации, а затем реализуется интерфейс обратного вызова сканирования для возврата информации о сканировании, включая начало, остановку сканирования и информацию о том, выполняется ли сканирование. Вы можете использовать этот класс напрямую или инкапсулировать его в BleCore. Здесь мы инкапсулируем его в BleCore и модифицируем код в BleCore следующим образом:
public class BleCore {
private static volatile BleCore mInstance;
private final BleScan bleScan;
public BleCore(Context context) {
//Сканирование Bluetooth
bleScan = BleScan.getInstance(context);
}
public static BleCore getInstance(Context context) {
if (mInstance == null) {
synchronized (BleCore.class) {
if (mInstance == null) {
mInstance = new BleCore(context);
}
}
}
return mInstance;
}
public void setPhyScanCallback(ScanCallback scanCallback) {
bleScan.setScanCallback(scanCallback);
}
public boolean isScanning() {
return bleScan.isScanning();
}
public void startScan() {
bleScan.startScan();
}
public void stopScan() {
bleScan.stopScan();
}
}
Здесь есть два основных бизнес-процесса: первый — мониторинг переключателя Bluetooth, а второй — применение динамических разрешений.
Прежде чем приступить к бизнес-обработке, мы сначала изменяем имя класса MyApplication на BleApp. После модификации мы меняем код внутри, как показано ниже:
public class BleApp extends AbilityPackage {
private static BleCore bleCore;
@Override
public void onInitialize() {
super.onInitialize();
bleCore = BleCore.getInstance(getContext());
}
public static BleCore getBleCore() {
return bleCore;
}
}
Сначала давайте взглянем на Жизненный. цикл среза,Это важнее,под我们首先существоватьcom.llw.ble
Создайте его подutils
Сумка,utils
Сумка Создайте его подLogUtilsдобрый,Код выглядит следующим образом:
public class LogUtils {
static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "HarmonyBle");
private static HiLogLabel logLabel;
public static void setLogLabel(HiLogLabel logLabel) {
LogUtils.logLabel = logLabel;
}
public static void Log(String content) {
HiLog.info(LABEL, content);
}
public static void LogI(String TAG, String content) {
HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, TAG);
HiLog.info(label, content);
}
public static void LogD(String TAG, String content) {
HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, TAG);
HiLog.debug(label, content);
}
public static void LogE(String TAG, String content) {
HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, TAG);
HiLog.error(label, content);
}
public static void LogW(String TAG, String content) {
HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, TAG);
HiLog.warn(label, content);
}
}
Это связано с тем, что печать журналов в Harmony затруднительна.,Итак, напишите класс инструмента,Инкапсулируйте это,под我们修改一下ScanSlice
добрыйсерединаизкод,Как показано ниже:
public class ScanSlice extends AbilitySlice {
private final String TAG = ScanSlice.class.getSimpleName();
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_slice_scan);
LogUtils.LogD(TAG, "onStart");
}
@Override
public void onActive() {
LogUtils.LogD(TAG, "onActive");
}
@Override
protected void onInactive() {
LogUtils.LogD(TAG, "onInactive");
}
@Override
public void onForeground(Intent intent) {
LogUtils.LogD(TAG, "onForeground");
}
@Override
protected void onBackground() {
LogUtils.LogD(TAG, "onBackground");
}
@Override
protected void onStop() {
LogUtils.LogD(TAG, "onStop");
}
}
Затем запустим его и проверим журнал консоли:
Затем возвращаемся на рабочий стол через клавишу Home и смотрим лог:
Далее нажимаем иконку на рабочем столе, чтобы вернуться в приложение и смотрим лог:
Возвращаемся на рабочий стол, а затем заходим в приложение через фоновую работающую программу и смотрим лог:
Логи этих двух способов возврата в приложение одинаковые. Затем нажимаем клавишу возврата для возврата на рабочий стол и смотрим логи:
Итак, теперь вы лучше понимаете жизненный цикл Slice. Давайте напишем код ниже.
ˆСначала решите проблемы, связанные с Bluetooth.,существоватьBleCore
середина添加如下код:
private final BluetoothHost mBluetoothHost;
создается в конструкторе
public BleCore(Context context) {
...
// Получите собственный объект управления Bluetooth.
mBluetoothHost = BluetoothHost.getDefaultHost(context);
}
Затем пишем еще два метода:
public boolean isEnableBt() {
return mBluetoothHost.getBtState() == BluetoothHost.STATE_ON;
}
public void enableBt() {
mBluetoothHost.enableBt();
}
используется для Определите, включен ли Bluetoothи открытьBluetooth,вернуться вScanSlice
середина我们需要使用BleCore
справитьсяBluetooth相关из工作,Код выглядит следующим образом:
public class ScanSlice extends AbilitySlice {
private final String TAG = ScanSlice.class.getSimpleName();
private BleCore bleCore;
private Text txScanStatus;
private ListContainer lcDevice;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_slice_scan);
bleCore = BleApp.getBleCore();
txScanStatus = (Text) findComponentById(ResourceTable.Id_tx_scan_status);
lcDevice = (ListContainer) findComponentById(ResourceTable.Id_lc_device);
//Наблюдение за кликами
txScanStatus.setClickedListener(component -> {
});
}
@Override
public void onActive() {
// Определите, включен ли Bluetooth
if (!bleCore.isEnableBt()) {
//Включаем Bluetooth
bleCore.enableBt();
return;
}
}
}
首先существоватьonStart()
середина对BleCoreсоздавать экземпляр,findComponentById
Точно так же, какfindViewById
,затем вonActive()
середина调用刚才我们所写изметод。
@Override
public void onActive() {
// Определите, включен ли Bluetooth
if (!bleCore.isEnableBt()) {
//Включаем Bluetooth
bleCore.enableBt();
return;
}
}
Затем происходит обработка разрешений на позиционирование. Также в onActive() добавьте следующий код:
@Override
public void onActive() {
// Определите, включен ли Bluetooth
...
// Получить ли позиционирование Разрешения
String locationPermission = "ohos.permission.LOCATION";
if (verifySelfPermission(locationPermission) != IBundleManager.PERMISSION_GRANTED) {
requestPermissionsFromUser(new String[]{locationPermission}, 100);
return;
}
}
Здесь мы сначала определяем разрешение, а затем определяем, следует ли его предоставить. Если нет, выполните запрос ниже, чтобы увидеть:
Затем мы завершили открытие и позиционирование динамического приложения «Разрешения» Bluetooth.,Вы можете запустить его один раз,ты найдешь,Вам также необходимо запросить Разрешения,Потому что DS не сохраняет данные приложения при установке по умолчанию.,И Bluetooth открывает системный уровень,Так что вам больше не придется включать Bluetooth,И нужно повторно запросить позиционирование,чтобы избежать этого,我们НажмитеRun→ Edit Configurations...
существовать弹出из窗口上勾选Keep Application Data
Нажмите «ОК» и запустите еще раз.
Далее мы приступаем к процессу сканирования и добавляем в ScanSlice следующий код метода:
private void startScan() {
bleCore.startScan();
txScanStatus.setText("Стоп");
}
private void stopScan() {
bleCore.stopScan();
txScanStatus.setText("Поиск");
}
Вот методы сканирования и остановки,Измените текстовый текст одновременно,существоватьonStart()
середина首先实现Сканировать обратный вызовмонитор,Потом обрабатывать и обрабатывать.txScanStatus
文本из Нажмите事件,Код выглядит следующим образом:
@Override
public void onStart(Intent intent) {
...
bleCore.setPhyScanCallback(this);
//Наблюдение за кликами
txScanStatus.setClickedListener(component -> {
if (bleCore.isScanning()) {
stopScan();//Переключатель сканирования Остановить сканирование
} else {
startScan();//Начать сканирование
}
});
}
здесьthis
Сообщим об ошибке,Наведите на него мышь,Alt + Входим, появляется всплывающее окно.
Выберите последний,сбудется для тебяScanCallback
серединаизonScanResult()
метод,Код выглядит следующим образом:
@Override
public void onScanResult(BleScanResult result) {
LogUtils.LogD(TAG, result.getPeripheralDevice().getDeviceAddr());
}
мы里面打印一下扫描到изоборудованиеMac-адрес,最后мыonActive()
середина增加如下所示код:
@Override
public void onActive() {
...
// Это сканирование?
if (!bleCore.isScanning()) {
startScan();
}
}
Запустите его ниже и посмотрите журнал консоли:
Он отсканирован, но пока не виден, поэтому нам нужно отрендерить его так, чтобы его можно было увидеть.
Чтобы отобразить устройство, сначала нам нужно написать Bean.
Создайте новый класс BleDevice в базовом пакете. Код внутри выглядит следующим образом:
public class BleDevice {
private String realName = "Unknown device"; //Настоящее имя устройства Bluetooth
private String macAddress; //адрес
private int rssi; //сила сигнала
private BlePeripheralDevice device; //оборудование
public BleDevice(BleScanResult scanResult) {
this.device = scanResult.getPeripheralDevice();
this.macAddress = device.getDeviceAddr();
String name = device.getDeviceName().get();
if (name != null || !name.isEmpty()) {
this.realName = name;
}
this.rssi = scanResult.getRssi();
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public String getMacAddress() {
return macAddress;
}
public void setMacAddress(String macAddress) {
this.macAddress = macAddress;
}
public int getRssi() {
return rssi;
}
public void setRssi(int rssi) {
this.rssi = rssi;
}
public BlePeripheralDevice getDevice() {
return device;
}
public void setDevice(BlePeripheralDevice device) {
this.device = device;
}
}
Об этом Бобе нечего сказать,Следующее, что нужно сделать, это отобразить элемент списка.,существоватьAndroidсередина我们使用из是适配器Adapter
,而существоватьHarmonyсередина使用из是поставщикProvider
。
Аналогично, давайте сначала напишем макет,существоватьlayoutСоздайте новый подitem_scan_device.xml
,Код выглядит следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_content"
ohos:width="match_parent"
ohos:alignment="vertical_center"
ohos:background_element="#FFF"
ohos:bottom_padding="8vp"
ohos:orientation="horizontal"
ohos:right_padding="16vp"
ohos:top_margin="1vp"
ohos:top_padding="8vp">
<Image
ohos:height="match_content"
ohos:width="match_content"
ohos:end_margin="16vp"
ohos:image_src="$graphic:ic_bluetooth"
ohos:start_margin="16vp"/>
<DirectionalLayout
ohos:height="match_content"
ohos:width="match_content"
ohos:orientation="vertical"
ohos:weight="1">
<Text
ohos:id="$+id:device_name"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="Имя устройства"
ohos:text_size="16fp"/>
<Text
ohos:id="$+id:device_address"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="Адрес устройства"
ohos:text_color="$color:gray"
ohos:text_size="14fp"
ohos:top_margin="4vp"/>
</DirectionalLayout>
<Text
ohos:id="$+id:rssi"
ohos:height="match_content"
ohos:width="match_content"
ohos:align_parent_end="true"
ohos:text_color="#000000"
ohos:text_size="10fp"/>
</DirectionalLayout>
Несколько основных материалов,Имя устройства, Mac-адрес, уровень сигнала Rssi,Тогда здесь есть значок,существоватьgraphic
Создайте его подic_bluetooth.xml
,Код выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<vector
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="48vp"
ohos:width="48vp"
ohos:viewportHeight="1024"
ohos:viewportWidth="1024">
<path
ohos:fillColor="#A7D3FF"
ohos:pathData="M53.31,512a458.69,458.69 0,1 1,917.38 0A458.69,458.69 0,0 1,53.31 512zM584.96,301.82a356.16,356.16 0,0 0,-39.81 -26.69c-12.1,-6.34 -32,-13.89 -52.74,-3.01 -20.48,10.82 -25.86,31.23 -27.78,44.67 -1.92,13.18 -1.92,30.21 -1.92,48.45v77.18l-57.92,-49.6a32,32 0,0 0,-41.6 48.64L445.44,512 363.2,582.4a32,32 0,1 0,41.6 48.64l57.92,-49.6v77.18c0,18.24 0,35.33 1.92,48.51 1.92,13.44 7.23,33.86 27.78,44.61 20.74,10.88 40.64,3.33 52.74,-2.94a356.48,356.48 0,0 0,39.81 -26.69l39.42,-28.8c10.62,-7.74 21.31,-15.55 29.06,-23.1 8.64,-8.58 18.56,-21.57 18.56,-40.06 0,-18.56 -9.92,-31.55 -18.56,-40.06 -7.68,-7.55 -18.43,-15.36 -29.06,-23.17L548.99,512l75.39,-54.98c10.62,-7.74 21.31,-15.55 29.06,-23.17 8.64,-8.51 18.56,-21.5 18.56,-40 0,-18.56 -9.92,-31.55 -18.56,-40.06 -7.68,-7.62 -18.43,-15.36 -29.06,-23.17l-39.42,-28.8zM526.72,367.36v64.77c0,7.36 0,11.01 2.37,12.16 2.3,1.28 5.25,-0.9 11.2,-5.25l44.8,-32.7 8.32,-6.08c3.97,-2.94 5.95,-4.42 5.95,-6.53 0,-2.18 -1.98,-3.65 -5.95,-6.53l-8.32,-6.14 -36.1,-26.3a3344.06,3344.06 0,0 0,-9.34 -6.78c-5.44,-3.97 -8.19,-5.95 -10.5,-4.8 -2.37,1.15 -2.37,4.54 -2.37,11.33v12.86zM526.72,656.45L526.72,591.74c0,-7.36 0,-11.01 2.37,-12.16 2.3,-1.22 5.25,0.96 11.2,5.25l44.8,32.7 8.32,6.14c3.97,2.88 5.95,4.35 5.95,6.53 0,2.11 -1.98,3.58 -5.95,6.53l-8.32,6.08 -36.1,26.37 -9.34,6.78c-5.44,3.97 -8.19,5.95 -10.5,4.74 -2.37,-1.15 -2.37,-4.48 -2.37,-11.33v-12.8z"></path>
</vector>
Далее мы пишем поставщика, создаем пакет поставщика в com.llw.ble и создаем класс ScanDeviceProvider в этом пакете. Код выглядит следующим образом:
public class ScanDeviceProvider extends BaseItemProvider {
private final List<BleDevice> deviceList;
private final AbilitySlice slice;
public ScanDeviceProvider(List<BleDevice> list, AbilitySlice slice) {
this.deviceList = list;
this.slice = slice;
}
@Override
public int getCount() {
return deviceList == null ? 0 : deviceList.size();
}
@Override
public Object getItem(int position) {
if (deviceList != null && position >= 0 && position < deviceList.size()) {
return deviceList.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public Component getComponent(int position, Component component, ComponentContainer componentContainer) {
final Component cpt;
ScanDeviceHolder holder;
BleDevice device = deviceList.get(position);
if (component == null) {
cpt = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_item_scan_device, null, false);
holder = new ScanDeviceHolder(cpt);
//Привязываем полученную информацию о субкомпоненте к экземпляру элемента списка
cpt.setTag(holder);
} else {
cpt = component;
// После получения экземпляра элемента списка из кэша напрямую используйте информацию о связанном подкомпоненте для заполнения данных.
holder = (ScanDeviceHolder) cpt.getTag();
}
holder.deviceName.setText(device.getRealName());
holder.deviceAddress.setText(device.getMacAddress());
holder.rssi.setText(String.format(Locale.getDefault(), "%d dBm", device.getRssi()));
return cpt;
}
/**
* Используется для сохранения информации о подкомпонентах элементов списка.
*/
public static class ScanDeviceHolder {
Text deviceName;
Text deviceAddress;
Text rssi;
public ScanDeviceHolder(Component component) {
deviceName = (Text) component.findComponentById(ResourceTable.Id_device_name);
deviceAddress = (Text) component.findComponentById(ResourceTable.Id_device_address);
rssi = (Text) component.findComponentById(ResourceTable.Id_rssi);
}
}
}
ˆКод поставщика,Видно, что написано аналогично адаптеру,不同из是你得注意getComponent()
методсерединаиз处理,Кроме того, поставщик по умолчанию предоставляет метод щелчка по товару.,Так что нам больше не придется писать это самим.
Вернёмся к ScanSlice. Сначала создадим несколько переменных. Код выглядит следующим образом:
private final List<BleDevice> mList = new ArrayList<>();
private ScanDeviceProvider provider;
Затем инициализируйте его в методе onStart():
@Override
public void onStart(Intent intent) {
...
provider = new ScanDeviceProvider(mList, this);
lcDevice.setItemProvider(provider);
//отслеживание кликов по элементам списка
lcDevice.setItemClickedListener((listContainer, component, position, id) -> {
});
}
Здесь мы настраиваем поставщик списка, затем добавляем прослушиватель кликов по элементу и, наконец, визуализируем данные в обратном вызове сканирования. Модифицированный код выглядит следующим образом:
private int findIndex(BleDevice bleDevice, List<BleDevice> deviceList) {
int index = 0;
for (final BleDevice devi : deviceList) {
if (bleDevice.getMacAddress().equals(devi.getDevice().getDeviceAddr())) return index;
index += 1;
}
return -1;
}
@Override
public void onScanResult(BleScanResult result) {
BleDevice bleDevice = new BleDevice(result);
int index = findIndex(bleDevice, mList);
if (index == -1) {
//Добавляем новое устройство
mList.add(bleDevice);
} else {
//Обновляем rssi и метку времени существующих устройств
mList.get(index).setRssi(bleDevice.getRssi());
}
getUITaskDispatcher().syncDispatch(() -> provider.notifyDataChanged());
}
здесь添加一个findIndex()
метод,Используется для добавления устройств и обновления устройств.,Наконец, синхронно обновите поставщика через поток пользовательского интерфейса.,Изменить другую Начать сканированиеи Остановить сканированиеизметодкод:
private void startScan() {
mList.clear();
provider.notifyDataChanged();
bleCore.startScan();
txScanStatus.setText("Стоп");
LogUtils.LogD(TAG,"Начать сканированиеоборудование!");
}
private void stopScan() {
bleCore.stopScan();
txScanStatus.setText("Поиск");
LogUtils.LogD(TAG,"уже Остановить сканированиеоборудование!");
}
Запустите его и увидите:
Если это тебе поможет, можешь также попробовать Стар или Форк. Горы высокие, а реки длинные~ Увидимся позже~
Адрес исходного кода:HarmonyBle-Java