鸿蒙跨端天气同步系统:多设备实时天气数据共享 原创

进修的泡芙
发布于 2025-6-18 21:21
浏览
0收藏

鸿蒙跨端天气同步系统:多设备实时天气数据共享

本文将基于HarmonyOS 5的分布式能力和ArkUI框架,实现一个支持多设备同步的天气查询应用,能够在不同设备间实时同步天气数据和城市偏好。

技术架构
数据获取层:调用公开天气API获取实时数据

数据处理层:解析和转换API返回的天气数据

分布式同步层:通过分布式数据管理实现多设备数据共享

UI展示层:响应式UI展示天气信息和同步状态

完整代码实现
天气数据模型定义

// model/WeatherData.ts
export class WeatherData {
city: string = ‘’; // 城市名称
temperature: number = 0; // 当前温度(℃)
weather: string = ‘’; // 天气状况
humidity: number = 0; // 湿度(%)
windSpeed: number = 0; // 风速(km/h)
airQuality: string = ‘’; // 空气质量
forecast: DailyForecast[] = []; // 天气预报
updateTime: number = 0; // 更新时间戳
deviceId: string = ‘’; // 最后更新的设备ID

constructor(data?: Partial<WeatherData>) {
if (data) {
Object.assign(this, data);
if (!this.updateTime) {
this.updateTime = Date.now();
}

}

export class DailyForecast {
date: string = ‘’; // 日期
dayWeather: string = ‘’; // 白天天气
nightWeather: string = ‘’; // 夜间天气
maxTemp: number = 0; // 最高温度
minTemp: number = 0; // 最低温度

天气API服务实现

// service/WeatherApiService.ts
import http from ‘@ohos.net.http’;
import { WeatherData, DailyForecast } from ‘…/model/WeatherData’;

const WEATHER_API_KEY = ‘YOUR_API_KEY’; // 替换为实际API Key
const API_URL = ‘https://api.openweathermap.org/data/2.5/weather’;

export class WeatherApiService {
private httpRequest = http.createHttp();

// 获取城市天气数据
async fetchWeatherData(city: string): Promise<WeatherData> {
return new Promise((resolve, reject) => {
this.httpRequest.request(
{API_URL}?q={city}&units=metric&appid=${WEATHER_API_KEY},
method: ‘GET’,

      header: { 'Content-Type': 'application/json' }
    },
    (err, data) => {
      if (err) {
        reject(err);
        return;

if (data.responseCode === 200) {

        const result = JSON.parse(data.result);
        const weather = this.parseWeatherData(result);
        resolve(weather);

else {

        reject(new Error(请求失败,状态码: ${data.responseCode}));

}

  );
});

// 解析API返回的天气数据

private parseWeatherData(data: any): WeatherData {
return new WeatherData({
city: data.name,
temperature: Math.round(data.main.temp),
weather: data.weather[0].main,
humidity: data.main.humidity,
windSpeed: data.wind.speed,
airQuality: this.getAirQuality(data.main.aqi),
forecast: this.parseForecast(data.forecast)
});
// 解析天气预报数据

private parseForecast(forecastData: any[]): DailyForecast[] {
return forecastData.slice(0, 5).map(item => ({
date: item.dt_txt,
dayWeather: item.weather[0].main,
nightWeather: item.weather[0].main, // 简化处理
maxTemp: Math.round(item.main.temp_max),
minTemp: Math.round(item.main.temp_min)
}));
// 获取空气质量描述

private getAirQuality(aqi: number): string {
if (aqi <= 50) return ‘优’;
if (aqi <= 100) return ‘良’;
if (aqi <= 150) return ‘轻度污染’;
if (aqi <= 200) return ‘中度污染’;
return ‘重度污染’;
}

分布式天气同步服务

// service/WeatherSyncService.ts
import distributedData from ‘@ohos.data.distributedData’;
import deviceInfo from ‘@ohos.deviceInfo’;
import { WeatherData } from ‘…/model/WeatherData’;

const STORE_ID = ‘weather_sync_store’;
const WEATHER_KEY = ‘current_weather’;

export class WeatherSyncService {
private kvManager: distributedData.KVManager;
private kvStore: distributedData.SingleKVStore;
private localDeviceId: string = deviceInfo.deviceId;

// 初始化分布式数据存储
async initialize() {
const config = {
bundleName: ‘com.example.weatherapp’,
userInfo: {
userId: ‘weather_user’,
userType: distributedData.UserType.SAME_USER_ID
};

this.kvManager = distributedData.createKVManager(config);
const options = {
  createIfMissing: true,
  encrypt: false,
  backup: false,
  autoSync: true,
  kvStoreType: distributedData.KVStoreType.SINGLE_VERSION
};

this.kvStore = await this.kvManager.getKVStore(STORE_ID, options);

// 订阅数据变更
this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => {
  this.handleDataChange(data);
});

// 处理数据变更

private handleDataChange(data: distributedData.ChangeNotification) {
if (data.insertEntries.length > 0 && data.insertEntries[0].key === WEATHER_KEY) {
const newWeather = JSON.parse(data.insertEntries[0].value.value);
AppStorage.setOrCreate(‘currentWeather’, new WeatherData(newWeather));
}

// 同步天气数据到所有设备
async syncWeatherData(weather: WeatherData) {
weather.deviceId = this.localDeviceId;
await this.kvStore.put(WEATHER_KEY, JSON.stringify(weather));
// 获取当前设备ID

getLocalDeviceId(): string {
return this.localDeviceId;
}

天气卡片组件实现

// components/WeatherCard.ets
import { WeatherData } from ‘…/model/WeatherData’;

@Component
export struct WeatherCard {
@Link currentWeather: WeatherData;
@State isExpanded: boolean = false;

build() {
Column() {
// 当前天气概览
Row() {
Column() {
Text(this.currentWeather.city)
.fontSize(20)
.fontWeight(FontWeight.Bold)

      Text(this.formatTime(this.currentWeather.updateTime))
        .fontSize(12)
        .fontColor('#888888')

.layoutWeight(1)

    Text(${this.currentWeather.temperature}°)
      .fontSize(48)
      .fontWeight(FontWeight.Bold)

.width(‘100%’)

  .padding(16)

  // 天气详情
  if (this.isExpanded) {
    Column() {
      Divider()
      
      // 天气状况
      Row() {
        WeatherDetailItem({
          icon: $r('app.media.ic_weather'),
          label: '天气',
          value: this.currentWeather.weather
        })
        
        WeatherDetailItem({
          icon: $r('app.media.ic_humidity'),
          label: '湿度',
          value: ${this.currentWeather.humidity}%
        })

.margin({ top: 12, bottom: 12 })

      // 风速和空气质量
      Row() {
        WeatherDetailItem({
          icon: $r('app.media.ic_wind'),
          label: '风速',
          value: ${this.currentWeather.windSpeed}km/h
        })
        
        WeatherDetailItem({
          icon: $r('app.media.ic_air'),
          label: '空气质量',
          value: this.currentWeather.airQuality
        })

// 天气预报

      Text('未来5天预报')
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 8 })
      
      ForEach(this.currentWeather.forecast, (item: DailyForecast) => {
        ForecastItem({ forecast: item })
      })

.padding(16)

// 展开/收起按钮

  Row() {
    Image($r('app.media.ic_arrow'))
      .width(20)
      .height(20)
      .rotate({ angle: this.isExpanded ? 180 : 0 })
    
    Text(this.isExpanded ? '收起' : '查看更多')
      .fontSize(14)
      .margin({ left: 4 })

.justifyContent(FlexAlign.Center)

  .width('100%')
  .padding(8)
  .onClick(() => {
    animateTo({ duration: 300 }, () => {
      this.isExpanded = !this.isExpanded;
    });
  })

.width(‘100%’)

.backgroundColor('#FFFFFF')
.borderRadius(12)
.shadow({ radius: 4, color: '#10000000', offsetX: 0, offsetY: 2 })

// 格式化时间显示

private formatTime(timestamp: number): string {
const date = new Date(timestamp);
return {date.getHours().toString().padStart(2, ‘0’)}:{date.getMinutes().toString().padStart(2, ‘0’)} 更新;
}

@Component
struct WeatherDetailItem {
private icon: Resource;
private label: string;
private value: string;

build() {
Row() {
Image(this.icon)
.width(24)
.height(24)
.margin({ right: 8 })

  Column() {
    Text(this.label)
      .fontSize(12)
      .fontColor('#888888')
    
    Text(this.value)
      .fontSize(16)
      .fontWeight(FontWeight.Medium)

}

.layoutWeight(1)

}

@Component
struct ForecastItem {
private forecast: DailyForecast;

build() {
Row() {
Text(this.forecast.date)
.fontSize(14)
.layoutWeight(1)

  Row() {
    Text(${this.forecast.maxTemp}°)
      .fontSize(14)
      .fontColor('#FF5722')
    
    Text(${this.forecast.minTemp}°)
      .fontSize(14)
      .fontColor('#2196F3')
      .margin({ left: 8 })

Text(this.forecast.dayWeather)

    .fontSize(14)
    .margin({ left: 16 })

.padding(8)

.width('100%')

}

天气主页面实现

// pages/WeatherPage.ets
import { WeatherApiService } from ‘…/service/WeatherApiService’;
import { WeatherSyncService } from ‘…/service/WeatherSyncService’;
import { WeatherCard } from ‘…/components/WeatherCard’;

@Entry
@Component
struct WeatherPage {
private apiService: WeatherApiService = new WeatherApiService();
private syncService: WeatherSyncService = new WeatherSyncService();
@StorageLink(‘currentWeather’) currentWeather: WeatherData = new WeatherData();
@State cityInput: string = ‘北京’;
@State isLoading: boolean = false;
@State isSynced: boolean = false;

async aboutToAppear() {
await this.syncService.initialize();
this.isSynced = true;
await this.loadWeatherData(this.cityInput);
build() {

Column() {
  // 城市搜索栏
  Row() {
    TextInput({ text: this.cityInput, placeholder: '输入城市名称' })
      .layoutWeight(1)
      .onSubmit((value: string) => {
        if (value) {
          this.loadWeatherData(value);

})

    Button('搜索')
      .margin({ left: 8 })
      .onClick(() => {
        if (this.cityInput) {
          this.loadWeatherData(this.cityInput);

})

.width(‘90%’)

  .margin({ top: 20, bottom: 16 })

  // 加载状态
  if (this.isLoading) {
    LoadingProgress()
      .width(50)
      .height(50)
      .margin({ top: 100 })

else if (this.currentWeather.city) {

    // 天气卡片
    WeatherCard({ currentWeather: $currentWeather })
      .width('90%')
      .margin({ bottom: 20 })

    // 同步状态
    Row() {
      Circle()
        .width(10)
        .height(10)
        .fill(this.isSynced ? '#4CAF50' : '#F44336')
        .margin({ right: 5 })
      
      Text(this.isSynced ? '已连接多设备' : '单机模式')
        .fontSize(14)
        .fontColor('#666666')

}

.width(‘100%’)

.height('100%')

// 加载天气数据

private async loadWeatherData(city: string) {
this.isLoading = true;
try {
const weather = await this.apiService.fetchWeatherData(city);
this.currentWeather = weather;
await this.syncService.syncWeatherData(weather);
catch (err) {

  prompt.showToast({ message: '获取天气数据失败', duration: 2000 });

finally {

  this.isLoading = false;

}

实现原理详解
数据获取与同步流程:

主设备调用天气API获取最新数据

数据解析后同步到分布式数据库

其他设备通过订阅机制接收更新

所有设备保持天气数据一致
UI响应机制:

使用@StorageLink绑定天气数据

数据变更自动触发UI更新

展开/收起动画使用animateTo实现平滑过渡
设备协同原理:

每个设备都可以作为数据源更新天气

显示最后更新设备的ID

冲突时以最后更新的数据为准

扩展功能建议
多城市管理:

  // 添加多城市支持

async addFavoriteCity(city: string) {
await this.kvStore.put(city_${city}, JSON.stringify({
city,
lastUpdate: Date.now()
}));

天气预警通知:

  // 检查极端天气条件

function checkWeatherAlert(weather: WeatherData) {
if (weather.weather = ‘暴雨’ || weather.airQuality = ‘重度污染’) {
showNotification(‘天气预警’, 当前{weather.city}有{weather.weather}天气,请注意安全);
}

天气趋势图表:

  // 使用图表库展示温度变化趋势

import charts from ‘@ohos.charts’;

function renderTemperatureChart(forecast: DailyForecast[]) {
const data = forecast.map(item => ({
date: item.date,
temp: item.maxTemp
}));
// 渲染折线图…

总结

本文展示了如何利用HarmonyOS的分布式能力构建一个多设备同步的天气应用。通过将天气数据存储在分布式数据库中,实现了多设备间的实时数据同步,确保用户在不同设备上都能获取一致的天气信息。

这种架构不仅适用于天气应用,也可以扩展到新闻、等需要实时数据同步的场景。合理利用鸿蒙的分布式能力,可以大大简化多设备协同开发的复杂度,提升用户体验。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2025-6-18 21:22:10修改
收藏
回复
举报
回复
    相关推荐