HarmonyOS 5开发从入门到精通(十六):天气应用实战(下)
HarmonyOS 5开发从入门到精通(十六):天气应用实战(下)
本章将继续完善天气应用,重点实现服务卡片、跨设备数据同步和高级功能,打造一个功能完整的天气应用。
一、核心概念
1. 服务卡片与原子化服务
服务卡片是HarmonyOS的特色功能,允许应用核心功能以卡片形式展示在桌面,无需打开完整应用。原子化服务进一步将应用功能拆分为独立服务单元,实现跨设备无缝体验。
2. 分布式数据管理
HarmonyOS的分布式数据管理能力使应用能够在多个设备间同步数据。通过分布式数据库KVStore,天气数据可以在手机、平板、智慧屏等设备间实时同步。
二、关键API详解
1. 服务卡片开发
// 卡片配置文件
"forms": [
{
"name": "weather_widget",
"description": "天气服务卡片",
"src": "./ets/WeatherWidgetExtension/WeatherCard.ets",
"window": { "designWidth": 360 },
"updateEnabled": true,
"scheduledUpdateTime": 30, // 30分钟定时更新
"defaultDimension": "2 * 2",
"supportDimensions": ["2 * 2", "2 * 4"]
}
]
2. FormExtensionAbility
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility'
export default class WeatherWidgetExtension extends FormExtensionAbility {
// 卡片创建时调用
async onAddForm(want: Want): Promise<formBindingData.FormBindingData> {
const weatherData = await this.fetchWeatherData()
return formBindingData.createFormBindingData(weatherData)
}
// 卡片更新时调用
async onUpdateForm(formId: string): Promise<void> {
const newData = await this.fetchWeatherData()
await formProvider.updateForm(formId,
formBindingData.createFormBindingData(newData))
}
}
3. 分布式数据同步
import distributedKVStore from '@ohos.data.distributedKVStore'
// 创建分布式数据管理器
const kvManager = distributedKVStore.createKVManager({
bundleName: 'com.example.weatherapp',
userInfo: { userId: '0', userType: distributedKVStore.UserType.SAME_USER_ID }
})
// 获取KVStore实例
const kvStore = await kvManager.getKVStore('weather_store', {
createIfMissing: true,
autoSync: true, // 开启自动同步
kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION
})
4. 数据变化监听
// 订阅数据变更事件
kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL,
(data) => {
this.handleDataChange(data)
}
)
// 处理数据变更
private handleDataChange(data: distributedKVStore.ChangeNotification) {
if (data.insertEntries.length > 0) {
const newWeather = JSON.parse(data.insertEntries[0].value.value)
this.updateWeatherDisplay(newWeather)
}
}
5. 地理位置服务
import geolocation from '@ohos.geolocation'
// 获取当前位置
async getCurrentLocation(): Promise<string> {
try {
const location = await geolocation.getCurrentLocation({
timeout: 30000,
coordinateType: geolocation.CoordinateType.WGS84
})
return `${location.longitude},${location.latitude}`
} catch (error) {
return '北京' // 默认城市
}
}
6. 动画效果
// 天气图标旋转动画
@State rotateAngle: number = 0
Image(this.weatherIcon)
.rotate({ angle: this.rotateAngle })
.onClick(() => {
animateTo({ duration: 1000 }, () => {
this.rotateAngle = 360
this.rotateAngle = 0
})
})
7. 本地存储
import preferences from '@ohos.data.preferences'
// 保存用户偏好设置
async saveUserPreferences(): Promise<void> {
const prefs = await preferences.getPreferences(this.context, 'weather_prefs')
await prefs.put('favoriteCity', this.currentCity)
await prefs.flush()
}
8. 后台任务管理
import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'
// 申请后台运行权限
async requestBackgroundPermission(): Promise<void> {
try {
await backgroundTaskManager.requestSuspendDelay()
} catch (error) {
console.error('后台权限申请失败')
}
}
三、实战案例
完整代码实现
import distributedKVStore from '@ohos.data.distributedKVStore'
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility'
import formBindingData from '@ohos.app.form.formBindingData'
// 天气服务卡片Ability
@Entry
@Component
struct WeatherWidgetExtension extends FormExtensionAbility {
@State currentWeather: WeatherData = new WeatherData()
private kvStore: distributedKVStore.SingleKVStore | null = null
async onAddForm(want: Want): Promise<formBindingData.FormBindingData> {
await this.initDistributedData()
await this.loadWeatherData()
return this.createBindingData()
}
async onUpdateForm(formId: string): Promise<void> {
await this.loadWeatherData()
const bindingData = this.createBindingData()
await formProvider.updateForm(formId, bindingData)
}
// 初始化分布式数据
private async initDistributedData() {
const kvManager = distributedKVStore.createKVManager({
bundleName: 'com.example.weather',
userInfo: { userId: '0', userType: distributedKVStore.UserType.SAME_USER_ID }
})
this.kvStore = await kvManager.getKVStore('weather_store', {
createIfMissing: true,
autoSync: true
})
// 监听数据变化
this.kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL,
(data) => this.onDataChanged(data))
}
// 加载天气数据
private async loadWeatherData(): Promise<void> {
try {
// 尝试从分布式存储获取数据
const syncedData = await this.getSyncedData()
if (syncedData) {
this.currentWeather = syncedData
return
}
// 从网络API获取数据
const apiData = await this.fetchFromAPI()
this.currentWeather = apiData
// 同步到其他设备
await this.syncData(apiData)
} catch (error) {
console.error('加载天气数据失败:', error)
}
}
// 创建绑定数据
private createBindingData(): formBindingData.FormBindingData {
return formBindingData.createFormBindingData({
city: this.currentWeather.city,
temperature: `${this.currentWeather.temp}℃`,
condition: this.currentWeather.condition,
updateTime: this.formatTime(new Date())
})
}
build() {
Column() {
// 城市名称
Text(this.currentWeather.city)
.fontSize(16)
.fontColor(Color.White)
.margin({ bottom: 8 })
// 温度和天气状况
Row() {
Text(this.currentWeather.temp.toString())
.fontSize(24)
.fontColor(Color.White)
.fontWeight(FontWeight.Bold)
Text('℃')
.fontSize(16)
.fontColor(Color.White)
.margin({ left: 2, top: 4 })
}
.margin({ bottom: 4 })
Text(this.currentWeather.condition)
.fontSize(14)
.fontColor(Color.White)
// 更新时间
Text(this.formatTime(new Date()))
.fontSize(12)
.fontColor('#CCFFFFFF')
.margin({ top: 8 })
}
.width('100%')
.height('100%')
.backgroundColor('#4A90E2')
.padding(16)
}
}
// 增强型天气页面组件
@Component
struct EnhancedWeatherPage {
@State currentWeather: WeatherData = new WeatherData()
@State favoriteCities: string[] = []
@State isConnected: boolean = false
private syncService: WeatherSyncService = new WeatherSyncService()
async aboutToAppear() {
await this.syncService.initialize()
this.isConnected = this.syncService.isConnected
await this.loadFavoriteCities()
await this.loadWeatherData()
}
build() {
Column() {
// 连接状态指示器
this.buildConnectionStatus()
// 多城市管理
this.buildCityManager()
// 增强型天气卡片
EnhancedWeatherCard({ weatherData: this.currentWeather })
// 天气预报列表
WeatherForecastList()
}
}
@Builder
private buildConnectionStatus() {
Row() {
Circle()
.width(8)
.height(8)
.fill(this.isConnected ? '#4CAF50' : '#FF6B6B')
.margin({ right: 8 })
Text(this.isConnected ? '多设备已连接' : '单设备模式')
.fontSize(14)
.fontColor('#666666')
}
.margin({ top: 10, bottom: 10 })
}
@Builder
private buildCityManager() {
Column() {
Text('收藏城市')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Scroll() {
Row() {
ForEach(this.favoriteCities, (city: string) => {
Text(city)
.fontSize(14)
.padding(8)
.backgroundColor('#F0F0F0')
.borderRadius(4)
.margin({ right: 8 })
.onClick(() => this.switchCity(city))
})
}
.padding(10)
}
}
.margin({ bottom: 20 })
}
}
// 分布式天气同步服务
class WeatherSyncService {
private kvStore: distributedKVStore.SingleKVStore | null = null
public isConnected: boolean = false
async initialize(): Promise<void> {
const kvManager = distributedKVStore.createKVManager({
bundleName: 'com.example.weather',
userInfo: { userId: '0', userType: distributedKVStore.UserType.SAME_USER_ID }
})
this.kvStore = await kvManager.getKVStore('weather_sync', {
createIfMissing: true,
autoSync: true
})
this.isConnected = true
}
async syncWeatherData(weather: WeatherData): Promise<void> {
if (!this.kvStore) return
try {
await this.kvStore.put('current_weather', JSON.stringify(weather))
} catch (error) {
console.error('数据同步失败:', error)
}
}
}
四、总结
✅ 关键知识点
- 服务卡片的生命周期管理和定时更新机制
- 分布式数据同步的实现原理和跨设备通信
- 多城市管理和用户偏好设置的本地存储
- 天气应用的性能优化和用户体验提升
🔧 核心API列表
FormExtensionAbility- 服务卡片基础能力distributedKVStore- 分布式数据存储管理formBindingData.createFormBindingData()- 卡片数据绑定backgroundTaskManager- 后台任务管理preferences- 本地偏好设置存储animateTo- 属性动画实现
💡 应用建议
- 服务卡片更新频率要合理平衡,避免频繁更新耗电
- 分布式数据同步要考虑网络状况,实现优雅降级
- 多设备适配时要考虑不同屏幕尺寸的布局优化
- 建议实现数据缓存策略,提升离线使用体验
通过本章学习,你已经掌握了HarmonyOS天气应用的完整开发流程。下一章我们将开始新闻阅读应用的实战开发。
浙公网安备 33010602011771号