从零开始纯血鸿蒙天气预报-数据库(storm)

97 阅读2分钟

易得天气

天气预报需要添加数据库能力,用以保存城市的天气数据

数据库使用的是:storm

"@zxhhyj/storm": "^2.0.2"

创建数据库

class AppDatabase extends Database {
  initDb(context: Context): Promise<relationalStore.RdbStore> {
    return relationalStore.getRdbStore(context, { name: "app.db", securityLevel: relationalStore.SecurityLevel.S1 })
  }

  readonly cityDataDao = TableCityData
}

export const myDatabase = Storm
  .databaseBuilder(AppDatabase)
  .setVersion(1)// 设置数据库的版本
  .addMigrations(AutoMigration)// 设置当数据库未初始化时自动初始化,初始化后的版本号为 setVersion 设置版本号,即 1
  .build()

定义表和实体

export interface CityData {
  id?: number
  key: string
  city_level_name?: string
  name?: string
  street?: string
  country?: string
  upper?: string
  prov?: string
  prov_en?: string
  cityid?: string
  city_level_id?: string
  isLocationCity: boolean
  weatherData?: SimpleWeatherData
}

export class CityDataTable extends Table<CityData> {
  readonly tableName = 't_city_data'
  readonly id = Column.integer('id').primaryKey(true).bindTo(this, 'id')
  readonly key = Column.text('key').default('').bindTo(this, 'key')
  readonly city_level_name = Column.text('city_level_name').default('').bindTo(this, 'city_level_name')
  readonly name = Column.text('name').default('').bindTo(this, 'name')
  readonly street = Column.text('street').default('').bindTo(this, 'street')
  readonly country = Column.text('country').default('').bindTo(this, 'country')
  readonly upper = Column.text('upper').default('').bindTo(this, 'upper')
  readonly prov = Column.text('prov').default('').bindTo(this, 'prov')
  readonly prov_en = Column.text('prov_en').default('').bindTo(this, 'prov_en')
  readonly cityid = Column.text('cityid').default('').bindTo(this, 'cityid')
  readonly city_level_id = Column.text('city_level_id').default('').bindTo(this, 'city_level_id')
  readonly isLocationCity = Column.boolean('isLocationCity').default(0).bindTo(this, 'isLocationCity')
  readonly weatherData =
    Column.references('simple_weather_data_id', TableSimpleWeatherData).default(null).bindTo(this, 'weatherData')
}

export const TableCityData = new CityDataTable()
export interface SimpleWeatherData {
  id?: number
  city: string
  temp: number
  tempHigh: number
  tempLow: number
  weatherType: string
  weatherDesc: string
  sunrise: string
  sunset: string
}

export class SimpleWeatherDataTable extends Table<SimpleWeatherData> {
  readonly tableName = 't_simple_weather_data'
  readonly id = Column.integer('id').primaryKey(true).bindTo(this, 'id')
  readonly city = Column.text('city').default('').bindTo(this, 'city')
  readonly temp = Column.integer('temp').default(0).bindTo(this, 'temp')
  readonly tempHigh = Column.integer('tempHigh').default(0).bindTo(this, 'tempHigh')
  readonly tempLow = Column.integer('tempLow').default(0).bindTo(this, 'tempLow')
  readonly weatherType = Column.text('weatherType').default('').bindTo(this, 'weatherType')
  readonly weatherDesc = Column.text('weatherDesc').default('').bindTo(this, 'weatherDesc')
  readonly sunrise = Column.text('sunrise').default('').bindTo(this, 'sunrise')
  readonly sunset = Column.text('sunset').default('').bindTo(this, 'sunset')
}

export const TableSimpleWeatherData = new SimpleWeatherDataTable()

初始化数据库

export class AppAbilityStage extends AbilityStage {
  async onCreate(): Promise<void> {
    // 应用HAP首次加载时触发,可以在此执行该Module的初始化操作(例如资源预加载、线程创建等)。
    // 在module.json5配置文件中,通过配置 srcEntry 参数来指定模块对应的代码路径,以作为HAP加载的入口。
    // 初始化路由
    ZRouter.initialize((config) => {
      config.isLoggingEnabled = BuildProfile.DEBUG
      config.isHSPModuleDependent = true
      // 服务路由初始化配置,如果没有使用服务路由,可不设置
      // config.loadDynamicModule = ['@hzw/hara', 'harb', 'hspc']
      config.onDynamicLoadComplete = () => {
        console.log("已完成所有模块的加载")
      }
    })

    await myDatabase.init(this.context)
  }
}

闪屏页修改

@Route({ name: RouterConstants.SPLASH_PAGE })
@ComponentV2
export struct SplashPage {
  build() {
    NavDestination() {
      Column() {
        Image($r('app.media.splash'))
          .width('100%')
          .height('100%')
          .objectFit(ImageFit.Cover)
      }
    }
    .hideTitleBar(true)
    .height('100%')
    .width('100%')
    .onAppear(() => {
      Logger.e('SplashPage aboutToAppear')
      setTimeout(() => {
        this.handle()
      }, 800)
    })
    .onBackPressed(() => {
      console.log('onBackPressed');
      return true
    })
  }

  handle() {
    myDatabase.beginAsync((db) => {
      let locationCity = db.cityDataDao.firstOrNull(it => it.equalTo(TableCityData.key, Constants.LOCATION_CITY_ID))
      Logger.e('locationCity = ' + locationCity)
      if (locationCity == null) {
        locationCity = {
          key: Constants.LOCATION_CITY_ID,
          isLocationCity: true
        }
        db.cityDataDao.add(locationCity)
      }
      let currentCityId = PreferencesUtil.getStringSync(Constants.CURRENT_CITY_ID)
      if (StrUtil.isNotEmpty(locationCity?.cityid) || StrUtil.isNotEmpty(currentCityId)) {
        let currentCity = db.cityDataDao.firstOrNull(it => it.equalTo(TableCityData.key, currentCityId))
        Logger.e('currentCity = ' + currentCity)
        ZRouter.getInstance().replace(RouterConstants.WEATHER_MAIN_PAGE)
      } else {
        ZRouter.getInstance().replace(RouterConstants.SELECT_CITY_PAGE)
      }
    })
  }
}

新增选择城市页面

@Route({ name: RouterConstants.SELECT_CITY_PAGE })
@ComponentV2
export struct SelectCityPage {
  @Computed
  get exitApp() {
    return ZRouter.getInstance().getAllPathName().length <= 1;
  }

  @Builder
  SearchContent() {
    Search({
      placeholder: '搜索城市(中文/拼音)',
      icon: '/resources/base/media/ic_search_home.webp',
    })
      .backgroundColor($r('app.color.card_color_02'))
      .placeholderFont({ size: 16 })
      .placeholderColor($r('app.color.color_999999'))
      .searchIcon({ color: $r('app.color.color_999999') })
      .padding({ left: 8, right: 8 })
      .layoutWeight(1)
  }

  build() {
    NavDestination() {
      Column() {
        Row() {
          this.SearchContent()
          if (!this.exitApp) {
            Text('取消')
              .clickEffect({ level: ClickEffectLevel.HEAVY, scale: 0.8 })
              .fontColor($r('app.color.color_999999'))
              .fontSize(16)
              .padding(8)
              .onClick(() => {
                ZRouter.getInstance().pop()
              })
          }
        }
        .padding({
          left: 16,
          top: 8,
          right: 8,
          bottom: 8,
        })

        Text('城市选择页面')
          .fontColor(Color.Black)
          .fontSize(16)
          .layoutWeight(1)
      }
      .width('100%')
      .height('100%')
    }
    .hideTitleBar(true)
    .padding({ top: px2vp(AppUtil.getStatusBarHeight()) })
    .height('100%')
    .width('100%')
    .onBackPressed(() => {
      if (this.exitApp) {
        AppUtil.getContext().terminateSelf()
        return true
      }
      return false
    })
  }
}

逻辑是首次进app由于没有保存的城市数据,先进入城市选择页面让用户添加城市数据,下次进入app就直接展示天气页面

效果图

2025-02-13 17.16.58.gif