DevicePicker集成HarmonyOS APP
在分布式应用中,经常需要让用户选择目标设备——比如视频通话选择哪个摄像头、音乐播放选择哪个音箱、文件传输选择哪个设备……如果每次都要自己实现设备列表UI、设备过滤、设备选择逻辑,开发成本会很高。HarmonyOS提供了DevicePicker组件,一行代码就能实现专业的设备选择功能。这篇文章带你深入理解DevicePicker的使用与定制。
一、背景与动机:为什么需要DevicePicker?
1.1 设备选择的复杂性
在分布式场景下,设备选择面临诸多挑战:
设备多样性:不同设备类型、不同能力、不同状态,需要根据场景过滤合适的设备。
UI一致性:每个应用都需要设备选择功能,如果各自实现,UI风格不统一,用户体验差。
交互复杂性:设备选择不仅是点击选中,还涉及设备状态显示、能力展示、搜索过滤等复杂交互。
开发成本高:从设备发现、设备过滤、UI渲染、状态更新到选择回调,完整实现需要大量代码。
1.2 DevicePicker的价值
DevicePicker是HarmonyOS提供的系统级设备选择组件,它封装了设备选择的完整流程:

DevicePicker的核心价值:
| 特性 | 说明 | 开发价值 |
|---|---|---|
| 系统级UI | 统一的设备选择界面 | 无需自己实现UI |
| 智能过滤 | 根据场景自动过滤设备 | 简化过滤逻辑 |
| 状态展示 | 实时显示设备状态 | 无需自己监听状态 |
| 能力展示 | 展示设备能力信息 | 无需自己查询能力 |
| 回调封装 | 封装选择结果回调 | 简化交互逻辑 |
二、核心原理:DevicePicker工作机制
2.1 组件架构
2.1.1 组件结构
// DevicePicker组件配置
interface DevicePickerConfig {
// 基础配置
title?: string; // 标题
subtitle?: string; // 副标题
mode?: DevicePickerMode; // 选择模式
// 设备过滤
filter?: DeviceFilter; // 设备过滤器
excludeDevices?: string[]; // 排除的设备列表
// UI配置
showDeviceType?: boolean; // 是否显示设备类型
showDeviceState?: boolean; // 是否显示设备状态
showDeviceCapability?: boolean; // 是否显示设备能力
showSearchBar?: boolean; // 是否显示搜索栏
// 交互配置
multiSelect?: boolean; // 是否多选
maxSelectCount?: number; // 最大选择数量
confirmText?: string; // 确认按钮文本
cancelText?: string; // 取消按钮文本
// 回调配置
onDeviceSelected?: (device: DeviceInfo) => void; // 单选回调
onDevicesSelected?: (devices: DeviceInfo[]) => void; // 多选回调
onCancelled?: () => void; // 取消回调
}
// 选择模式
enum DevicePickerMode {
SINGLE = 'single', // 单选模式
MULTI = 'multi', // 多选模式
CASCADE = 'cascade' // 级联选择模式
}
// 设备过滤器
interface DeviceFilter {
deviceTypes?: DeviceType[]; // 设备类型过滤
capabilities?: string[]; // 能力过滤
states?: DeviceState[]; // 状态过滤
trustLevels?: TrustLevel[]; // 信任等级过滤
customFilter?: (device: DeviceInfo) => boolean; // 自定义过滤
}
2.1.2 组件流程
sequenceDiagram
participant App as 应用
participant Picker as DevicePicker
participant Filter as 过滤器
participant UI as UI组件
participant User as 用户
Note over App: 1. 创建DevicePicker
App->>Picker: create(config)
Note over Picker: 2. 初始化
Picker->>Picker: loadDevices()
Picker->>Filter: applyFilter(devices)
Filter-->>Picker: filteredDevices
Note over Picker: 3. 渲染UI
Picker->>UI: render(filteredDevices)
Note over User: 4. 用户交互
User->>UI: 选择设备
UI->>Picker: handleSelect(device)
alt 单选模式
Picker->>Picker: validateSelection(device)
Picker->>App: onDeviceSelected(device)
else 多选模式
User->>UI: 继续选择
UI->>Picker: handleSelect(device2)
User->>UI: 点击确认
UI->>Picker: confirmSelection()
Picker->>App: onDevicesSelected(devices)
end
classDef primary fill:#4A90E2,stroke:#2E5C8A,stroke-width:2px,color:#fff
classDef warning fill:#F5A623,stroke:#C17A00,stroke-width:2px,color:#fff
classDef info fill:#7ED321,stroke:#5BA315,stroke-width:2px,color:#fff
class App,User primary
class Picker,Filter warning
class UI info
2.2 设备过滤机制
2.2.1 过滤流程
graph TD
Start[开始过滤] --> Load[加载设备列表]
Load --> Type{设备类型过滤?}
Type -->|是| FilterType[按类型过滤]
Type -->|否| Cap
FilterType --> Cap
Cap{能力过滤?}
Cap -->|是| FilterCap[按能力过滤]
Cap -->|否| State
FilterCap --> State
State{状态过滤?}
State -->|是| FilterState[按状态过滤]
State -->|否| Trust
FilterState --> Trust
Trust{信任等级过滤?}
Trust -->|是| FilterTrust[按信任等级过滤]
Trust -->|否| Custom
FilterTrust --> Custom
Custom{自定义过滤?}
Custom -->|是| FilterCustom[执行自定义过滤]
Custom -->|否| Sort
FilterCustom --> Sort
Sort[设备排序]
Sort --> Result[返回过滤结果]
classDef primary fill:#4A90E2,stroke:#2E5C8A,stroke-width:2px,color:#fff
classDef warning fill:#F5A623,stroke:#C17A00,stroke-width:2px,color:#fff
classDef info fill:#7ED321,stroke:#5BA315,stroke-width:2px,color:#fff
class Start,Load,Sort,Result primary
class Type,Cap,State,Trust,Custom warning
class FilterType,FilterCap,FilterState,FilterTrust,FilterCustom info
2.2.2 过滤实现
/**
* 设备过滤器实现
*/
class DeviceFilterImpl {
/**
* 应用过滤器
*/
applyFilter(
devices: DeviceInfo[],
filter: DeviceFilter
): DeviceInfo[] {
let filtered = [...devices];
// 设备类型过滤
if (filter.deviceTypes && filter.deviceTypes.length > 0) {
filtered = filtered.filter(device =>
filter.deviceTypes!.includes(device.deviceType)
);
}
// 能力过滤
if (filter.capabilities && filter.capabilities.length > 0) {
filtered = filtered.filter(device =>
this.hasCapabilities(device, filter.capabilities!)
);
}
// 状态过滤
if (filter.states && filter.states.length > 0) {
filtered = filtered.filter(device =>
filter.states!.includes(device.state)
);
}
// 信任等级过滤
if (filter.trustLevels && filter.trustLevels.length > 0) {
filtered = filtered.filter(device =>
filter.trustLevels!.includes(device.trustLevel)
);
}
// 自定义过滤
if (filter.customFilter) {
filtered = filtered.filter(filter.customFilter);
}
return filtered;
}
/**
* 检查设备是否有指定能力
*/
private hasCapabilities(
device: DeviceInfo,
capabilities: string[]
): boolean {
for (const cap of capabilities) {
if (!device.capabilities.includes(cap)) {
return false;
}
}
return true;
}
}
2.3 设备排序机制
/**
* 设备排序策略
*/
enum DeviceSortStrategy {
RECENTLY_USED = 'recently_used', // 最近使用
ALPHABETICAL = 'alphabetical', // 字母顺序
DEVICE_TYPE = 'device_type', // 设备类型
TRUST_LEVEL = 'trust_level', // 信任等级
STATE_PRIORITY = 'state_priority' // 状态优先级
}
/**
* 设备排序器
*/
class DeviceSorter {
/**
* 排序设备列表
*/
sort(
devices: DeviceInfo[],
strategy: DeviceSortStrategy
): DeviceInfo[] {
const sorted = [...devices];
switch (strategy) {
case DeviceSortStrategy.RECENTLY_USED:
sorted.sort((a, b) => b.lastUsedTime - a.lastUsedTime);
break;
case DeviceSortStrategy.ALPHABETICAL:
sorted.sort((a, b) => a.deviceName.localeCompare(b.deviceName));
break;
case DeviceSortStrategy.DEVICE_TYPE:
sorted.sort((a, b) => a.deviceType - b.deviceType);
break;
case DeviceSortStrategy.TRUST_LEVEL:
sorted.sort((a, b) => b.trustLevel - a.trustLevel);
break;
case DeviceSortStrategy.STATE_PRIORITY:
sorted.sort((a, b) =>
this.getStatePriority(b.state) - this.getStatePriority(a.state)
);
break;
}
return sorted;
}
/**
* 获取状态优先级
*/
private getStatePriority(state: DeviceState): number {
const priorityMap = {
[DeviceState.READY]: 5,
[DeviceState.ONLINE]: 4,
[DeviceState.IDLE]: 3,
[DeviceState.BUSY]: 2,
[DeviceState.SLEEP]: 1,
[DeviceState.OFFLINE]: 0
};
return priorityMap[state] || 0;
}
}
三、代码实战:DevicePicker使用
3.1 基础使用
import { DevicePicker, DevicePickerDialog } from '@ohos.distributedHardware.devicePicker';
/**
* DevicePicker基础使用示例
*/
@Component
export struct DevicePickerBasicExample {
@State selectedDevice: DeviceInfo | null = null;
build() {
Column() {
// 显示已选设备
if (this.selectedDevice) {
Row() {
Text(`已选设备: ${this.selectedDevice.deviceName}`)
.fontSize(16)
Blank()
Button('重新选择')
.onClick(() => {
this.showDevicePicker();
})
}
.width('100%')
.padding(16)
} else {
Button('选择设备')
.width('80%')
.height(48)
.onClick(() => {
this.showDevicePicker();
})
}
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
/**
* 显示设备选择器
*/
private showDevicePicker(): void {
// 创建设备选择器对话框
DevicePickerDialog.show({
title: '选择设备',
subtitle: '请选择目标设备',
mode: DevicePickerMode.SINGLE,
// 设备过滤
filter: {
states: [DeviceState.READY, DeviceState.ONLINE]
},
// UI配置
showDeviceType: true,
showDeviceState: true,
showSearchBar: true,
// 选择回调
onDeviceSelected: (device: DeviceInfo) => {
console.info(`选中设备: ${device.deviceName}`);
this.selectedDevice = device;
},
// 取消回调
onCancelled: () => {
console.info('取消选择');
}
});
}
}
3.2 场景化使用
/**
* DevicePicker场景化封装
*/
export class SceneDevicePicker {
/**
* 选择摄像头设备
*/
static async pickCamera(): Promise<DeviceInfo | null> {
return new Promise(resolve => {
DevicePickerDialog.show({
title: '选择摄像头',
subtitle: '选择用于拍照或录像的摄像头',
filter: {
capabilities: ['sensor.camera.front', 'sensor.camera.back'],
states: [DeviceState.READY]
},
onDeviceSelected: (device) => {
resolve(device);
},
onCancelled: () => {
resolve(null);
}
});
});
}
/**
* 选择显示设备(投屏)
*/
static async pickDisplay(): Promise<DeviceInfo | null> {
return new Promise(resolve => {
DevicePickerDialog.show({
title: '选择显示设备',
subtitle: '选择投屏目标设备',
filter: {
deviceTypes: [DeviceType.TV, DeviceType.PC, DeviceType.TABLET],
capabilities: ['output.display'],
states: [DeviceState.READY, DeviceState.ONLINE]
},
showDeviceCapability: true,
onDeviceSelected: (device) => {
resolve(device);
},
onCancelled: () => {
resolve(null);
}
});
});
}
/**
* 选择音频输出设备
*/
static async pickAudioOutput(): Promise<DeviceInfo | null> {
return new Promise(resolve => {
DevicePickerDialog.show({
title: '选择音频设备',
subtitle: '选择音频播放设备',
filter: {
capabilities: ['output.speaker', 'output.headphone'],
states: [DeviceState.READY]
},
onDeviceSelected: (device) => {
resolve(device);
},
onCancelled: () => {
resolve(null);
}
});
});
}
/**
* 选择文件传输目标设备
*/
static async pickFileTransferTarget(): Promise<DeviceInfo | null> {
return new Promise(resolve => {
DevicePickerDialog.show({
title: '发送到设备',
subtitle: '选择接收文件的设备',
filter: {
capabilities: ['storage'],
states: [DeviceState.READY, DeviceState.ONLINE]
},
showDeviceState: true,
onDeviceSelected: (device) => {
resolve(device);
},
onCancelled: () => {
resolve(null);
}
});
});
}
/**
* 选择健康监测设备
*/
static async pickHealthDevice(): Promise<DeviceInfo | null> {
return new Promise(resolve => {
DevicePickerDialog.show({
title: '选择健康设备',
subtitle: '选择用于健康监测的设备',
filter: {
deviceTypes: [DeviceType.WATCH],
capabilities: ['sensor.heartrate', 'sensor.spo2'],
states: [DeviceState.READY]
},
onDeviceSelected: (device) => {
resolve(device);
},
onCancelled: () => {
resolve(null);
}
});
});
}
/**
* 多设备选择
*/
static async pickMultipleDevices(
maxCount: number = 5
): Promise<DeviceInfo[]> {
return new Promise(resolve => {
DevicePickerDialog.show({
title: '选择设备',
subtitle: `最多选择${maxCount}个设备`,
mode: DevicePickerMode.MULTI,
multiSelect: true,
maxSelectCount: maxCount,
filter: {
states: [DeviceState.READY, DeviceState.ONLINE]
},
onDevicesSelected: (devices) => {
resolve(devices);
},
onCancelled: () => {
resolve([]);
}
});
});
}
}
3.3 自定义DevicePicker组件
/**
* 自定义设备选择器组件
* 提供更灵活的定制能力
*/
@Component
export struct CustomDevicePicker {
// 配置参数
@Prop title: string = '选择设备';
@Prop filter: DeviceFilter = {};
@Prop multiSelect: boolean = false;
@Prop maxSelectCount: number = 1;
// 状态
@State devices: DeviceInfo[] = [];
@State filteredDevices: DeviceInfo[] = [];
@State selectedDevices: Set<string> = new Set();
@State searchText: string = '';
@State loading: boolean = true;
// 回调
private onSelected?: (devices: DeviceInfo[]) => void;
private onCancelled?: () => void;
aboutToAppear(): void {
this.loadDevices();
}
/**
* 加载设备列表
*/
private async loadDevices(): Promise<void> {
this.loading = true;
try {
// 获取设备列表
const deviceMgr = deviceManager.createDeviceManager('com.example.app');
const allDevices = await deviceMgr.getTrustedDeviceList(true);
this.devices = allDevices;
// 应用过滤
this.applyFilter();
} catch (error) {
console.error(`加载设备失败: ${JSON.stringify(error)}`);
} finally {
this.loading = false;
}
}
/**
* 应用过滤
*/
private applyFilter(): void {
let filtered = [...this.devices];
// 应用配置的过滤器
const filterImpl = new DeviceFilterImpl();
filtered = filterImpl.applyFilter(filtered, this.filter);
// 应用搜索过滤
if (this.searchText) {
filtered = filtered.filter(device =>
device.deviceName.toLowerCase().includes(this.searchText.toLowerCase())
);
}
this.filteredDevices = filtered;
}
build() {
Column() {
// 标题栏
Row() {
Text(this.title)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Blank()
Button('取消')
.fontSize(14)
.backgroundColor(Color.Transparent)
.fontColor('#666666')
.onClick(() => {
this.onCancelled?.();
})
}
.width('100%')
.padding(16)
Divider()
// 搜索栏
Row() {
TextInput({ placeholder: '搜索设备' })
.width('100%')
.height(40)
.onChange((value) => {
this.searchText = value;
this.applyFilter();
})
}
.width('100%')
.padding({ left: 16, right: 16, top: 12, bottom: 12 })
Divider()
// 设备列表
if (this.loading) {
Column() {
LoadingProgress()
.width(48)
.height(48)
Text('加载中...')
.fontSize(14)
.fontColor('#999999')
.margin({ top: 12 })
}
.width('100%')
.layoutWeight(1)
.justifyContent(FlexAlign.Center)
} else if (this.filteredDevices.length === 0) {
Column() {
Text('暂无设备')
.fontSize(16)
.fontColor('#999999')
}
.width('100%')
.layoutWeight(1)
.justifyContent(FlexAlign.Center)
} else {
List() {
ForEach(this.filteredDevices, (device: DeviceInfo) => {
ListItem() {
this.DeviceItem(device)
}
}, (device: DeviceInfo) => device.deviceId)
}
.width('100%')
.layoutWeight(1)
}
Divider()
// 底部操作栏
Row() {
Text(`已选${this.selectedDevices.size}个设备`)
.fontSize(14)
.fontColor('#666666')
Blank()
Button('确认')
.fontSize(16)
.height(40)
.enabled(this.selectedDevices.size > 0)
.onClick(() => {
this.confirmSelection();
})
}
.width('100%')
.padding(16)
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
@Builder
DeviceItem(device: DeviceInfo) {
Row() {
// 选择指示器(多选模式)
if (this.multiSelect) {
Checkbox()
.select(this.selectedDevices.has(device.deviceId))
.onChange((checked) => {
this.handleSelect(device, checked);
})
.margin({ right: 12 })
}
// 设备图标
Circle()
.width(48)
.height(48)
.fill(this.getDeviceColor(device.deviceType))
// 设备信息
Column() {
Text(device.deviceName)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Row() {
Text(this.getDeviceTypeText(device.deviceType))
.fontSize(12)
.fontColor('#999999')
Text(' · ')
.fontSize(12)
.fontColor('#999999')
Text(this.getStateText(device.state))
.fontSize(12)
.fontColor(this.getStateColor(device.state))
}
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Start)
.margin({ left: 12 })
.layoutWeight(1)
// 单选模式的选择指示器
if (!this.multiSelect) {
Radio({ value: device.deviceId, group: 'devicePicker' })
.checked(this.selectedDevices.has(device.deviceId))
.onChange((checked) => {
if (checked) {
this.handleSelect(device, true);
}
})
}
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(8)
.margin({ bottom: 8 })
.onClick(() => {
if (!this.multiSelect) {
this.handleSelect(device, true);
}
})
}
/**
* 处理设备选择
*/
private handleSelect(device: DeviceInfo, selected: boolean): void {
if (selected) {
if (this.multiSelect) {
// 多选模式
if (this.selectedDevices.size < this.maxSelectCount) {
this.selectedDevices.add(device.deviceId);
}
} else {
// 单选模式
this.selectedDevices.clear();
this.selectedDevices.add(device.deviceId);
}
} else {
this.selectedDevices.delete(device.deviceId);
}
}
/**
* 确认选择
*/
private confirmSelection(): void {
const selected = this.filteredDevices.filter(
device => this.selectedDevices.has(device.deviceId)
);
this.onSelected?.(selected);
}
/**
* 获取设备类型文本
*/
private getDeviceTypeText(type: DeviceType): string {
const typeMap: Record<number, string> = {
[DeviceType.PHONE]: '手机',
[DeviceType.TABLET]: '平板',
[DeviceType.WATCH]: '手表',
[DeviceType.TV]: '电视',
[DeviceType.PC]: '电脑'
};
return typeMap[type] || '设备';
}
/**
* 获取设备颜色
*/
private getDeviceColor(type: DeviceType): ResourceColor {
const colorMap: Record<number, ResourceColor> = {
[DeviceType.PHONE]: '#4A90E2',
[DeviceType.TABLET]: '#7ED321',
[DeviceType.WATCH]: '#F5A623',
[DeviceType.TV]: '#9B59B6',
[DeviceType.PC]: '#E74C3C'
};
return colorMap[type] || '#999999';
}
/**
* 获取状态文本
*/
private getStateText(state: DeviceState): string {
const stateMap: Record<DeviceState, string> = {
[DeviceState.OFFLINE]: '离线',
[DeviceState.ONLINE]: '在线',
[DeviceState.READY]: '就绪',
[DeviceState.BUSY]: '繁忙',
[DeviceState.SLEEP]: '休眠',
[DeviceState.ERROR]: '错误',
[DeviceState.UNKNOWN]: '未知'
};
return stateMap[state] || '未知';
}
/**
* 获取状态颜色
*/
private getStateColor(state: DeviceState): ResourceColor {
if (state === DeviceState.READY || state === DeviceState.ONLINE) {
return '#7ED321';
}
if (state === DeviceState.OFFLINE || state === DeviceState.ERROR) {
return '#D0021B';
}
return '#F5A623';
}
/**
* 设置选择回调
*/
setOnSelected(callback: (devices: DeviceInfo[]) => void): this {
this.onSelected = callback;
return this;
}
/**
* 设置取消回调
*/
setOnCancelled(callback: () => void): this {
this.onCancelled = callback;
return this;
}
}
3.4 DevicePicker集成示例
/**
* DevicePicker集成示例
* 展示在实际应用中的使用
*/
@Component
export struct DevicePickerIntegrationExample {
@State currentScene: string = '';
@State selectedDevice: DeviceInfo | null = null;
build() {
Column() {
// 场景选择
Row() {
Text('选择场景:')
.fontSize(16)
Blank()
Button('视频通话')
.onClick(() => this.handleScene('video_call'))
Button('音乐播放')
.onClick(() => this.handleScene('music'))
Button('文件传输')
.onClick(() => this.handleScene('file'))
}
.width('100%')
.padding(16)
Divider()
// 结果展示
Column() {
if (this.selectedDevice) {
Text(`已选择设备: ${this.selectedDevice.deviceName}`)
.fontSize(18)
.fontWeight(FontWeight.Medium)
Text(`设备类型: ${this.selectedDevice.deviceType}`)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 8 })
Text(`设备状态: ${this.selectedDevice.state}`)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 4 })
} else {
Text('请选择场景并选择设备')
.fontSize(16)
.fontColor('#999999')
}
}
.width('100%')
.layoutWeight(1)
.justifyContent(FlexAlign.Center)
}
.width('100%')
.height('100%')
}
/**
* 处理场景选择
*/
private async handleScene(scene: string): Promise<void> {
this.currentScene = scene;
switch (scene) {
case 'video_call':
// 视频通话场景:选择有摄像头和麦克风的设备
this.selectedDevice = await SceneDevicePicker.pickCamera();
break;
case 'music':
// 音乐播放场景:选择音频输出设备
this.selectedDevice = await SceneDevicePicker.pickAudioOutput();
break;
case 'file':
// 文件传输场景:选择存储设备
this.selectedDevice = await SceneDevicePicker.pickFileTransferTarget();
break;
}
if (this.selectedDevice) {
// 执行场景相关操作
this.executeSceneAction(scene, this.selectedDevice);
}
}
/**
* 执行场景操作
*/
private executeSceneAction(scene: string, device: DeviceInfo): void {
console.info(`执行场景操作: ${scene}, 设备: ${device.deviceName}`);
// 根据场景执行不同操作
switch (scene) {
case 'video_call':
// 启动视频通话
this.startVideoCall(device);
break;
case 'music':
// 切换音频输出
this.switchAudioOutput(device);
break;
case 'file':
// 发送文件
this.sendFile(device);
break;
}
}
// 场景操作实现(简化)
private startVideoCall(device: DeviceInfo): void {
console.info(`启动视频通话,使用设备: ${device.deviceName}`);
}
private switchAudioOutput(device: DeviceInfo): void {
console.info(`切换音频输出到: ${device.deviceName}`);
}
private sendFile(device: DeviceInfo): void {
console.info(`发送文件到: ${device.deviceName}`);
}
}
四、踩坑与注意事项
4.1 过滤相关
坑1:过滤条件过严导致无设备
// ❌ 错误做法:过滤条件过严
filter: {
deviceTypes: [DeviceType.WATCH],
capabilities: ['sensor.camera.front'], // 手表通常没有前置摄像头
states: [DeviceState.READY]
}
// ✅ 正确做法:合理设置过滤条件
filter: {
deviceTypes: [DeviceType.WATCH],
capabilities: ['sensor.heartrate'], // 手表有心率传感器
states: [DeviceState.READY, DeviceState.ONLINE] // 包含在线状态
}
坑2:忘记处理取消情况
// ❌ 错误做法:只处理选择,不处理取消
onDeviceSelected: (device) => {
this.selectedDevice = device;
}
// ✅ 正确做法:同时处理取消
onDeviceSelected: (device) => {
this.selectedDevice = device;
},
onCancelled: () => {
console.info('用户取消选择');
// 可以显示提示或执行其他操作
}
4.2 UI相关
坑3:设备列表不刷新
设备状态变化后,DevicePicker列表未更新。
// ✅ 正确做法:监听设备状态变化并刷新
aboutToAppear(): void {
// 监听设备状态变化
deviceMgr.on('deviceStateChange', () => {
// 刷新设备列表
this.loadDevices();
});
}
坑4:多选数量限制未生效
// ✅ 正确做法:在handleSelect中检查数量限制
private handleSelect(device: DeviceInfo, selected: boolean): void {
if (selected && this.multiSelect) {
if (this.selectedDevices.size >= this.maxSelectCount) {
// 已达到最大选择数量,提示用户
this.showToast(`最多选择${this.maxSelectCount}个设备`);
return;
}
this.selectedDevices.add(device.deviceId);
}
}
4.3 性能相关
坑5:大量设备导致性能问题
// ✅ 正确做法:实现虚拟滚动或分页加载
List() {
ForEach(this.filteredDevices, (device: DeviceInfo) => {
ListItem() {
this.DeviceItem(device)
}
}, (device: DeviceInfo) => device.deviceId)
}
.cachedCount(5) // 缓存5个ListItem
五、HarmonyOS 6适配指南
5.1 API变更
DevicePicker API增强:
// HarmonyOS 5.0
DevicePickerDialog.show({
title: '选择设备',
onDeviceSelected: callback
});
// HarmonyOS 6.0
import { DevicePicker } from '@ohos.distributedHardware.devicePicker';
// 支持更多配置
DevicePicker.show({
title: '选择设备',
// 新增:智能推荐
recommendation: {
enabled: true,
strategy: 'AI_BASED' // AI推荐策略
},
// 新增:设备分组
grouping: {
enabled: true,
groupBy: 'DEVICE_TYPE' // 按设备类型分组
},
// 新增:设备预览
preview: {
enabled: true,
showCapability: true,
showStatus: true
},
onDeviceSelected: callback
});
5.2 行为变更
变更1:智能推荐
HarmonyOS 6新增AI智能推荐能力。
// HarmonyOS 6新增智能推荐
const recommendation = await DevicePicker.getRecommendation({
context: 'video_call', // 当前场景
history: true // 基于历史数据
});
console.info(`推荐设备: ${recommendation.devices}`);
变更2:设备预览
// HarmonyOS 6新增设备预览
DevicePicker.show({
preview: {
enabled: true,
onPreview: async (device) => {
// 返回预览内容
return {
thumbnail: await this.getDeviceThumbnail(device),
description: this.getDeviceDescription(device)
};
}
}
});
六、总结
DevicePicker是HarmonyOS提供的系统级设备选择组件,通过封装设备发现、过滤、排序、UI渲染、交互回调等完整流程,大幅简化了设备选择的开发成本。
核心要点回顾:
- 组件架构:配置驱动的设备选择组件
- 设备过滤:多维度过滤能力
- 设备排序:多种排序策略
- 场景封装:常用场景的快速选择
最佳实践建议:
- 合理设置过滤条件,避免无设备可选
- 同时处理选择和取消回调
- 监听设备状态变化并刷新列表
- 检查多选数量限制
- 实现虚拟滚动优化性能
- 使用兼容层适配多版本API
DevicePicker让设备选择从"重复造轮子"升级到"一行代码搞定",是提升分布式应用开发效率的利器。
- 点赞
- 收藏
- 关注作者
评论(0)