【高心星出品】
文章目錄
- 歡迎頁面效果
- 數據字典
- 創建數據庫表格
- Splash頁面
- 頁面功能
- 歡迎頁代碼
- 亮點
項目按照從數據庫連接層–視圖層–業務邏輯層這種三層架構開發,所以先設計了數據庫表格的結構,在EntryAbility中創建表格。
歡迎頁面效果
數據字典
- searchmodel的數據字典:
/***** 搜索歷史記錄模型*** 用于存儲用戶搜索關鍵詞的歷史記錄***/*export interface SearchHistoryItem {id?: number *// 記錄ID,可選*keyword: string *// 搜索關鍵詞*timestamp?: string *// 搜索時間戳,可選*}
- adcode的數據字典:
/***** 城市編碼模型*** 用于存儲城市相關的編碼信息***/*export interface adcode {id: number *// 城市ID*pid?: number *// 父級ID,可選*city_code: string *// 城市編碼*city_name: string *// 城市名稱*post_code?: string *// 郵政編碼,可選*area_code?: string *// 區號,可選*ctime?: string *// 創建時間,可選*}
這兩個模型的主要用途:
SearchHistoryItem:
-
用于記錄用戶的搜索歷史
-
包含搜索關鍵詞和時間信息
-
可用于實現搜索歷史功能
adcode:
-
用于存儲城市信息
-
包含城市編碼、名稱等基本信息
-
支持城市層級關系(通過pid)
-
包含郵政和區號等附加信息
創建數據庫表格
編寫DbUtils實現對于表格的創建。
-
創建名為 weatherinfo.db 的數據庫
-
設置數據庫安全級別為 S1
-
初始化兩個數據表:
-
t_adcode:存儲城市信息
-
t_search:存儲搜索歷史
import { relationalStore } from "@kit.ArkData";/***作者:gxx*時間:2025/4/21 9:16*功能:數據庫操作**/
// 城市編碼表名
export const TABLENAME: string = 't_adcode'// 搜索歷史表名
export const TABLENAME1: string = 't_search'// 數據庫配置
const CONFIG: relationalStore.StoreConfig = {name: 'weatherinfo.db', // 數據庫名稱securityLevel: relationalStore.SecurityLevel.S1 // 安全級別
}/*** 獲取數據庫實例* @param context 上下文對象* @returns 數據庫實例*/
export async function getrdb(context: Context) {return relationalStore.getRdbStore(context, CONFIG)
}/*** 創建數據庫表* @param context 上下文對象* @description 創建城市編碼表和搜索歷史表*/
export async function createtable(context: Context) {try {// 創建城市編碼表SQL語句let sql = 'CREATE TABLE IF NOT EXISTS t_adcode (\n' +' id INTEGER PRIMARY KEY AUTOINCREMENT,\n' + // 自增主鍵'name TEXT NOT NULL, code VARCHAR(50) NOT NULL,\n' + // 城市名稱和編碼' city VARCHAR(50) \n' + // 所屬城市');'// 創建搜索歷史表SQL語句let sql1 = 'CREATE TABLE IF NOT EXISTS t_search (\n' +' id INTEGER PRIMARY KEY AUTOINCREMENT,\n' + // 自增主鍵'keyword TEXT NOT NULL, timestamp VARCHAR(50) NOT NULL);' // 搜索關鍵詞和時間戳// 獲取數據庫實例并執行SQLlet rdb = await getrdb(context)rdb.executeSync(sql)rdb.executeSync(sql1)} catch (e) {console.error('dbutils 創建表格失敗: ', JSON.stringify(e))}
}
在EntryAbility中創建表格。
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { createtable } from '../utils/Dbutils';const DOMAIN = 0x0000;export default class EntryAbility extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');}onDestroy(): void {hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');}async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {// 1. 記錄窗口創建日志hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');// 2. 創建數據庫表格// 創建adcode和search_history兩個表格用于存儲城市代碼和搜索歷史await createtable(this.context)// 3. 加載啟動頁面// 加載splash頁面,splash頁面會檢查是否已導入城市數據// 如果未導入則會從cityma.txt讀取并導入數據庫// 導入完成后跳轉到主頁面IndexwindowStage.loadContent('pages/splash', async (err) => {if (err.code) {// 4. 加載失敗處理hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));return;}// 5. 加載成功記錄hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');});}onWindowStageDestroy(): void {// Main window is destroyed, release UI related resourceshilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');}onForeground(): void {// Ability has brought to foregroundhilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');}onBackground(): void {// Ability has back to backgroundhilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');}
}
Splash頁面
頁面功能
1.數據初始化:
-
頁面啟動時會檢查是否已經加載過城市數據(通過 PreferenceUtils 存儲的 isload 標志)
-
如果數據未加載,會執行 charu 函數來初始化數據
2.charu 函數的具體工作:
-
從資源文件中讀取 cityma.txt(城市碼數據文件)
-
將文件內容解析為 JSON 數據
-
通過 adcodedao 將城市數據插入到數據庫中
-
使用 @Concurrent 注解確保在后臺線程執行,避免阻塞主線程
3.界面展示:
-
顯示一個啟動圖片
-
展示一個環形進度條動畫
-
顯示"加載中…"文字
4.頁面跳轉:
- 數據加載完成后,會自動跳轉到主頁面(pages/Index)
歡迎頁代碼
import { adcodedao } from '../dao/adcodedao';
import { buffer, taskpool } from '@kit.ArkTS';
import { common } from '@kit.AbilityKit';
import { adcode } from '../model/adcode';
import { PreferenceUtils } from '../utils/PreferenceUtils';
import { router } from '@kit.ArkUI';/*** 插入城市數據到數據庫* @param context 上下文對象* @returns 插入是否成功*/
@Concurrent
async function charu(context: Context) {try {// 創建數據訪問對象let ad = new adcodedao(context)// 讀取原始文件內容let value = await context.resourceManager.getRawFileContent('cityma.txt')// 轉換為字符串let data = buffer.from(value).toString()// 解析JSON數據let content = JSON.parse(data) as adcode[]// 插入數據庫await ad.insert(content)return true} catch (e) {console.error('gxxt ', JSON.stringify(e))return false}
}// 持久化存儲的key名稱
const Prename: string = 'loaded'/*** 啟動頁面組件*/
@Entry
@Component
struct Splash {@State message: string = 'Hello World';// 進度條值@State value: number = 10// 上下文對象private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext// 定時器IDprivate intervalid: number = 0/*** 組件即將出現時的生命周期函數*/aboutToAppear(): void {// 設置定時器更新進度條this.intervalid = setInterval(() => {if (this.value == 100) {this.value = -10}this.value += 10}, 100)// 檢查是否已加載過數據let loaded = PreferenceUtils.getInstance(this.context, Prename).get('isload', false) as booleanif (loaded) {// 如果已加載過數據,直接跳轉到主頁router.replaceUrl({ url: 'pages/Index' })} else {// 如果未加載過數據,則讀取文件并插入數據庫taskpool.execute(charu, this.context).then((value) => {// 保存加載狀態PreferenceUtils.getInstance(this.context, Prename).putfile('isload', value as boolean)// 跳轉到主頁router.replaceUrl({ url: 'pages/Index' })})}}/*** 構建UI界面*/build() {Stack() {// 背景圖片Image($r('app.media.splash'))// 進度條Progress({ value: this.value, total: 100, type: ProgressType.ScaleRing }).width(100).height(100).backgroundColor(Color.Black).style({ strokeWidth: 15, scaleCount: 20, scaleWidth: 5 }).color(Color.White)// 加載提示文本Text('加載中...').fontWeight(FontWeight.Bolder)}.height('100%').width('100%').alignContent(Alignment.Center)}/*** 組件即將消失時的生命周期函數*/aboutToDisappear(): void {// 清除定時器clearInterval(this.intervalid)}
}
亮點
1.使用多線程將大量數據批量插入數據庫
批量插入:
/*** 批量插入城市數據到數據庫* @param acs 城市數據數組* @description 將城市數據批量插入到數據庫中* 如果城市數據包含ctime字段,則插入name、code、city三個字段* 否則只插入name和code兩個字段*/async insert(acs: adcode[]) {try {// 獲取數據庫實例let rdb = await getrdb(this.context)// 存儲要插入的數據let values: relationalStore.ValuesBucket[] = []// 遍歷城市數據acs.forEach((ac: adcode) => {let value: relationalStore.ValuesBucket// 判斷是否有ctime字段if (ac.ctime) {value = {'name': ac.city_name, // 城市名稱'code': ac.city_code, // 城市編碼'city': ac.ctime // 所屬城市}} else {value = {'name': ac.city_name, // 城市名稱'code': ac.city_code, // 城市編碼}}values.push(value)})// 批量插入數據rdb.batchInsertSync(TABLENAME, values)} catch (e) {console.error('gxxt adcodedao 插入數據錯誤: ', e.message)}}
多線程運行實體:
@Concurrent
async function charu(context: Context) {try {// 創建數據訪問對象let ad = new adcodedao(context)// 讀取原始文件內容let value = await context.resourceManager.getRawFileContent('cityma.txt')// 轉換為字符串let data = buffer.from(value).toString()// 解析JSON數據let content = JSON.parse(data) as adcode[]// 插入數據庫await ad.insert(content)return true} catch (e) {console.error('gxxt ', JSON.stringify(e))return false}
}
多線程執行:
// 如果未加載過數據,則讀取文件并插入數據庫taskpool.execute(charu, this.context).then((value) => {// 保存加載狀態PreferenceUtils.getInstance(this.context, Prename).putfile('isload', value as boolean)// 跳轉到主頁router.replaceUrl({ url: 'pages/Index' })})
2.使用Interval配合環形刻度進度條來制作動態的加載動畫
// 設置定時器更新進度條this.intervalid = setInterval(() => {if (this.value == 100) {this.value = -10}this.value += 10}, 100)
....................................// 進度條Progress({ value: this.value, total: 100, type: ProgressType.ScaleRing }).width(100).height(100).backgroundColor(Color.Black).style({ strokeWidth: 15, scaleCount: 20, scaleWidth: 5 }).color(Color.White)