HarmonyOS 5开发从入门到精通(十五):天气应用实战(上)

HarmonyOS 5开发从入门到精通(十五):天气应用实战(上)

本章将带领大家开发一个完整的天气应用,涵盖网络请求、JSON解析、UI展示等核心功能。通过本案例,你将掌握HarmonyOS应用开发的关键技能。

一、核心概念

1. 网络请求与数据模型

天气应用的核心是获取远程API数据并转换为本地数据模型。HarmonyOS提供了@ohos.net.http模块进行网络请求,配合JSON解析将服务器返回的数据转换为TypeScript对象,实现数据驱动UI。

2. 城市搜索与数据筛选

城市搜索功能通过监听输入框变化,实时过滤城市列表。结合ArkUI的响应式特性,当搜索关键词变化时,界面自动更新显示匹配结果。

二、关键API详解

1. 网络请求模块

import http from '@ohos.net.http'

// 创建HTTP请求实例
const httpRequest = http.createHttp()

// 发起GET请求
httpRequest.request(url, {
  method: http.RequestMethod.GET,
  connectTimeout: 10000,
  readTimeout: 10000
})

2. JSON解析

// 解析JSON字符串
const weatherData = JSON.parse(response.result)

// 转换为JSON字符串
const jsonStr = JSON.stringify(weatherData)

3. 天气数据模型

class WeatherModel {
  city: string = ''
  temperature: number = 0
  condition: string = ''
  humidity: number = 0
  windSpeed: number = 0
}

4. 城市搜索过滤

// 过滤城市列表
const filteredCities = cityList.filter(city => 
  city.name.includes(searchText)
)

5. 列表组件渲染

List() {
  ForEach(this.cityList, (city: CityInfo) => {
    ListItem() {
      Text(city.name)
    }
  })
}

6. 输入框组件

TextInput()
  .placeholder('搜索城市')
  .onChange((value: string) => {
    this.searchText = value
  })

7. 异步数据获取

async getWeatherData(city: string): Promise<WeatherModel> {
  try {
    const response = await httpRequest.request(url)
    return JSON.parse(response.result)
  } catch (error) {
    console.error('获取天气数据失败')
  }
}

8. 权限配置

{
  "requestPermissions": [
    {
      "name": "ohos.permission.INTERNET"
    }
  ]
}

9. 状态管理

@State weatherData: WeatherModel = new WeatherModel()
@State cityList: CityInfo[] = []
@State searchText: string = ''

10. 页面生命周期

aboutToAppear() {
  this.loadWeatherData()
}

onPageShow() {
  this.refreshData()
}

11. 错误处理

try {
  // 网络请求
} catch (error) {
  console.error('请求失败:', error)
}

12. 数据绑定

Text(this.weatherData.temperature + '°C')
  .fontSize(48)
  .fontColor(Color.White)

三、实战案例

完整代码实现

import http from '@ohos.net.http'
import { WeatherModel } from '../model/WeatherModel'

@Entry
@Component
struct WeatherApp {
  @State weatherData: WeatherModel = new WeatherModel()
  @State cityList: CityInfo[] = []
  @State searchText: string = ''
  @State filteredCities: CityInfo[] = []

  private httpRequest = http.createHttp()

  aboutToAppear() {
    this.loadCities()
    this.loadWeatherData('北京')
  }

  // 加载城市列表
  private loadCities() {
    this.cityList = [
      { name: '北京', code: '101010100' },
      { name: '上海', code: '101020100' },
      { name: '广州', code: '101280101' },
      { name: '深圳', code: '101280601' },
      { name: '杭州', code: '101210101' }
    ]
    this.filteredCities = this.cityList
  }

  // 获取天气数据
  private async loadWeatherData(city: string) {
    try {
      const url = `https://api.example.com/weather?city=${city}`
      const response = await this.httpRequest.request(url, {
        method: http.RequestMethod.GET
      })
      
      if (response.responseCode === 200) {
        const data = JSON.parse(response.result)
        this.weatherData = {
          city: data.city,
          temperature: data.temp,
          condition: data.condition,
          humidity: data.humidity,
          windSpeed: data.windSpeed
        }
      }
    } catch (error) {
      console.error('获取天气数据失败:', error)
    }
  }

  // 搜索城市
  private searchCities() {
    if (this.searchText === '') {
      this.filteredCities = this.cityList
    } else {
      this.filteredCities = this.cityList.filter(city =>
        city.name.includes(this.searchText)
      )
    }
  }

  build() {
    Column() {
      // 搜索框
      TextInput()
        .placeholder('搜索城市')
        .width('90%')
        .height(40)
        .backgroundColor(Color.White)
        .margin({ top: 20 })
        .onChange((value: string) => {
          this.searchText = value
          this.searchCities()
        })

      // 城市列表
      List() {
        ForEach(this.filteredCities, (city: CityInfo) => {
          ListItem() {
            Text(city.name)
              .fontSize(18)
              .margin({ left: 20 })
          }
          .onClick(() => {
            this.loadWeatherData(city.name)
          })
        })
      }
      .width('100%')
      .height('60%')

      // 天气信息展示
      Column() {
        Text(this.weatherData.city)
          .fontSize(24)
          .fontColor(Color.White)
        
        Text(this.weatherData.temperature + '°C')
          .fontSize(48)
          .fontColor(Color.White)
          .margin({ top: 10 })

        Text(this.weatherData.condition)
          .fontSize(16)
          .fontColor(Color.White)
          .margin({ top: 5 })

        Row() {
          Text('湿度: ' + this.weatherData.humidity + '%')
            .fontSize(14)
            .fontColor(Color.White)
          
          Text('风速: ' + this.weatherData.windSpeed + 'm/s')
            .fontSize(14)
            .fontColor(Color.White)
            .margin({ left: 20 })
        }
        .margin({ top: 10 })
      }
      .width('100%')
      .height('30%')
      .backgroundColor('#4A90E2')
      .padding(20)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
}

// 城市信息模型
interface CityInfo {
  name: string
  code: string
}

四、总结

关键知识点

  • 网络请求的异步处理与错误捕获
  • JSON数据的解析与模型转换
  • 城市搜索功能的实时过滤实现
  • 数据驱动UI的响应式更新机制

🔧 核心API列表

  • http.createHttp()- 创建HTTP请求实例
  • http.RequestMethod.GET- GET请求方法
  • JSON.parse()- JSON字符串解析
  • JSON.stringify()- 对象转JSON字符串
  • TextInput().onChange()- 输入框变化监听
  • ForEach()- 列表数据循环渲染
  • @State- 状态管理装饰器
  • async/await- 异步编程语法糖

💡 应用建议

  1. 网络请求建议使用try-catch包裹,处理网络异常
  2. 城市搜索可添加防抖优化,避免频繁触发过滤
  3. 天气数据可添加本地缓存,提升用户体验
  4. 建议使用真实的天气API(如和风天气、高德天气)替换示例中的模拟接口

通过本章学习,你已经掌握了天气应用的核心开发技能。下一章我们将继续完善应用,添加更多实用功能。

posted @ 2025-12-23 21:25  奇崽  阅读(0)  评论(0)    收藏  举报