鸿蒙 APP 开发:网络请求与数据持久化

核心内容
本文介绍鸿蒙应用开发中的网络通信与本地数据存储技术,涵盖官方 HTTP 请求库的使用、Preferences 轻量级存储及 SQLite 关系型数据库的集成方案。
主要内容:
- 掌握鸿蒙官方 HTTP 请求库的配置与使用;
- 实现商品列表与用户信息的网络请求交互;
- 理解数据持久化原理,使用 Preferences 与 SQLite 存储本地数据;
- 优化网络请求体验,包括加载动画、错误处理及网络状态检测。
一、网络请求基础
1.1 鸿蒙 HTTP 请求库
HarmonyOS Next 提供官方 HTTP 请求库,支持 HTTP/HTTPS 协议,功能包括发送 GET/POST/PUT/DELETE 请求、设置请求头与参数、文件上传下载、拦截器配置以及超时重试机制。
1.2 实战:HTTP 请求库配置
1. 配置网络权限
在 entry/src/main/module.json5 中添加网络权限:
{
"module": {
"requestPermissions": [
{"name": "ohos.permission.INTERNET"},
{"name": "ohos.permission.READ_NETWORK_STATE"},
{"name": "ohos.permission.WRITE_NETWORK_STATE"}
]
}
}
2. 网络请求工具类
创建 entry/src/main/ets/utils/HttpUtils.ets:
import http from '@ohos.net.http';
// 网络请求配置
const HTTP_CONFIG = {
baseUrl: 'https://api.example.com', // 替换为你的 API 地址
timeout: 10000, // 超时时间(毫秒)
retryCount: 3 // 重试次数
};
// 网络请求工具类
export class HttpUtils {
private static instance: HttpUtils | null = null;
private httpRequest: http.HttpRequest | null = null;
// 单例模式
static getInstance(): HttpUtils {
if (!HttpUtils.instance) {
HttpUtils.instance = new HttpUtils();
}
return HttpUtils.instance;
}
// 初始化 HTTP 请求
private initRequest(): void {
if (!this.httpRequest) {
this.httpRequest = http.createHttp();
}
}
// 发送 GET 请求
async get<T>(url: string, params?: Record<string, any>): Promise<T> {
this.initRequest();
const fullUrl = this.buildUrl(url, params);
const response = await this.httpRequest!.request(fullUrl, {
method: http.RequestMethod.GET,
header: { 'Content-Type': 'application/json' },
connectTimeout: HTTP_CONFIG.timeout,
readTimeout: HTTP_CONFIG.timeout
});
return this.handleResponse<T>(response);
}
// 发送 POST 请求
async post<T>(url: string, data?: Record<string, any>): Promise<T> {
this.initRequest();
const fullUrl = this.buildUrl(url);
const response = await this.httpRequest!.request(fullUrl, {
method: http.RequestMethod.POST,
header: { 'Content-Type': 'application/json' },
extraData: data,
connectTimeout: HTTP_CONFIG.timeout,
readTimeout: HTTP_CONFIG.timeout
});
return this.handleResponse<T>(response);
}
// 构建完整 URL
private buildUrl(url: string, params?: Record<string, any>): string {
let fullUrl = `${HTTP_CONFIG.baseUrl}${url}`;
if (params) {
const queryString = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&');
fullUrl += `?${queryString}`;
}
return fullUrl;
}
// 处理响应
private async handleResponse<T>(response: http.HttpResponse): Promise<T> {
if (response.responseCode === 200) {
const result = JSON.parse(response.result.toString());
if (result.code === 200) {
return result.data;
} else {
throw new Error(result.message || '请求失败');
}
} else {
throw new Error(`HTTP 错误:${response.responseCode}`);
}
}
}
二、网络请求实战
2.1 业务服务实现
1. 商品服务
创建 entry/src/main/ets/services/ProductService.ets:
import { HttpUtils } from '../utils/HttpUtils';
import { GoodsModel } from '../models/HomeModel';
// 商品 API 响应数据模型
export interface ProductResponseModel {
code: number;
message: string;
data: Array<GoodsModel>;
}
// 商品服务
export class ProductService {
private static instance: ProductService | null = null;
static getInstance(): ProductService {
if (!ProductService.instance) {
ProductService.instance = new ProductService();
}
return ProductService.instance;
}
// 获取商品列表
async getProductList(): Promise<Array<GoodsModel>> {
const response = await HttpUtils.getInstance().get<Array<GoodsModel>>('/api/products');
return response;
}
// 获取商品详情
async getProductDetail(id: number): Promise<GoodsModel> {
const response = await HttpUtils.getInstance().get<GoodsModel>(`/api/products/${id}`);
return response;
}
}
2. 用户服务
创建 entry/src/main/ets/services/UserService.ets:
import { HttpUtils } from '../utils/HttpUtils';
// 用户登录请求数据模型
export interface LoginRequestModel {
username: string;
password: string;
}
// 用户登录响应数据模型
export interface LoginResponseModel {
code: number;
message: string;
data: { token: string; userInfo: UserInfoModel; };
}
// 用户信息数据模型
export interface UserInfoModel {
id: number;
username: string;
avatar: string;
nickname: string;
email: string;
phone: string;
gender: number;
birthday: string;
}
// 用户服务
export class UserService {
private static instance: UserService | null = null;
static getInstance(): UserService {
if (!UserService.instance) {
UserService.instance = new UserService();
}
return UserService.instance;
}
// 用户登录
async login(request: LoginRequestModel): Promise<LoginResponseModel['data']> {
const response = await HttpUtils.getInstance().post<LoginResponseModel['data']>('/api/login', request);
return response;
}
// 用户注册
async register(request: LoginRequestModel): Promise<LoginResponseModel['data']> {
const response = await HttpUtils.getInstance().post<LoginResponseModel['data']>('/api/register', request);
return response;
}
// 获取用户信息
async getUserInfo(): Promise<UserInfoModel> {
const response = await HttpUtils.getInstance().get<UserInfoModel>('/api/user/info');
return response;
}
}
2.2 网络状态检测
1. 网络状态服务
创建 entry/src/main/ets/services/NetworkService.ets:
import network from '@ohos.net.network';
// 网络状态类型
export type NetworkType = 'wifi' | 'cellular' | 'none';
// 网络状态服务
export class NetworkService {
private static instance: NetworkService | null = null;
static getInstance(): NetworkService {
if (!NetworkService.instance) {
NetworkService.instance = new NetworkService();
}
return NetworkService.instance;
}
// 获取当前网络状态
getCurrentNetworkType(): NetworkType {
const networkType = network.getNetworkTypeSync();
switch (networkType) {
case network.NetworkType.WIFI:
return 'wifi';
case network.NetworkType.CELLULAR:
return 'cellular';
default:
return 'none';
}
}
// 监听网络状态变化
onNetworkTypeChange(callback: (type: NetworkType) => void): void {
network.on('netAvailable', () => {
callback(this.getCurrentNetworkType());
});
network.on('netUnavailable', () => {
callback('none');
});
}
}
2. 网络状态组件
创建 entry/src/main/ets/components/NetworkStatusComponent.ets:
import { NetworkService } from '../services/NetworkService';
@Component
export struct NetworkStatusComponent {
@State networkType: NetworkService.NetworkType = 'wifi';
build() {
Row({ space: 8 }) {
Image(this.networkType === 'wifi' ? $r('app.media.wifi') : this.networkType === 'cellular' ? $r('app.media.cellular') : $r('app.media.none'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain);
Text(this.networkType === 'wifi' ? 'WiFi' : this.networkType === 'cellular' ? '移动网络' : '无网络')
.fontSize(14)
.textColor(this.networkType === 'none' ? '#FF0000' : '#666666');
}
.width('auto')
.height('auto')
.padding(8, 16, 8, 16)
.backgroundColor(this.networkType === 'none' ? '#FFE0E0' : '#F5F5F5')
.borderRadius(20)
.visible(this.networkType === 'none');
}
aboutToAppear() {
this.networkType = NetworkService.getInstance().getCurrentNetworkType();
NetworkService.getInstance().onNetworkTypeChange((type: NetworkService.NetworkType) => {
this.networkType = type;
});
}
}
三、数据持久化实战
3.1 数据持久化分类
HarmonyOS Next 提供三种主要数据持久化方式:
| 方式 | 功能 | 适用场景 |
|---|---|---|
| Preferences | 轻量级存储,支持键值对存储 | 用户设置、应用配置、购物车数据等小体积数据 |
| SQLite | 关系型数据库,支持复杂查询 | 商品列表、用户信息、订单数据等结构化数据 |
| Distributed Data | 分布式存储,支持跨设备数据同步 | 超级终端多设备协同场景 |
3.2 实战:Preferences 存储
1. Preferences 工具类
创建 entry/src/main/ets/utils/PreferencesUtils.ets:
import preferences from '@ohos.data.preferences';
import { UIAbilityContext } from '@ohos.abilityAccessCtrl';
// Preferences 工具类
export class PreferencesUtils {
private static instance: PreferencesUtils | null = null;
private dataPreferences: preferences.Preferences | null = null;
static getInstance(): PreferencesUtils {
if (!PreferencesUtils.instance) {
PreferencesUtils.instance = new PreferencesUtils();
}
return PreferencesUtils.instance;
}
// 初始化 Preferences
async init(context: UIAbilityContext): Promise<void> {
if (!this.dataPreferences) {
this.dataPreferences = await preferences.getPreferences(context, 'app_preferences');
}
}
// 获取值
get<T>(key: string, defaultValue: T): T {
if (!this.dataPreferences) {
return defaultValue;
}
return this.dataPreferences.getSync(key, defaultValue) as T;
}
// 设置值
async put<T>(key: string, value: T): Promise<void> {
if (!this.dataPreferences) {
return;
}
await this.dataPreferences.put(key, value);
await this.dataPreferences.flush();
}
// 删除值
async delete(key: string): Promise<void> {
if (!this.dataPreferences) {
return;
}
await this.dataPreferences.delete(key);
await this.dataPreferences.flush();
}
// 清空所有值
async clear(): Promise<void> {
if (!this.dataPreferences) {
return;
}
const keys = this.dataPreferences.keys();
for (const key of keys) {
await this.dataPreferences.delete(key);
}
await this.dataPreferences.flush();
}
}
2. Preferences 应用
修改 entry/src/main/ets/services/UserService.ets:
import { HttpUtils } from '../utils/HttpUtils';
import { PreferencesUtils } from '../utils/PreferencesUtils';
// 用户服务
export class UserService {
// ... 其他方法
// 用户登录(添加 token 存储)
async login(request: LoginRequestModel): Promise<LoginResponseModel['data']> {
const response = await HttpUtils.getInstance().post<LoginResponseModel['data']>('/api/login', request);
// 存储 token 到 Preferences
await PreferencesUtils.getInstance().put('token', response.token);
return response;
}
// 获取用户信息(添加 token 认证)
async getUserInfo(): Promise<UserInfoModel> {
const token = PreferencesUtils.getInstance().get<string>('token', '');
HttpUtils.getInstance().addHeader('Authorization', `Bearer ${token}`);
const response = await HttpUtils.getInstance().get<UserInfoModel>('/api/user/info');
return response;
}
}
3.3 实战:SQLite 存储
1. SQLite 数据库管理类
创建 entry/src/main/ets/utils/SQLiteUtils.ets:
import relationalStore from '@ohos.data.relationalStore';
import { UIAbilityContext } from '@ohos.abilityAccessCtrl';
// 数据库配置
const DB_CONFIG = {
name: 'app_db.db',
securityLevel: relationalStore.SecurityLevel.S1
};
// SQLite 数据库管理类
export class SQLiteUtils {
private static instance: SQLiteUtils | null = null;
private rdbStore: relationalStore.RdbStore | null = null;
static getInstance(): SQLiteUtils {
if (!SQLiteUtils.instance) {
SQLiteUtils.instance = new SQLiteUtils();
}
return SQLiteUtils.instance;
}
// 初始化数据库
async init(context: UIAbilityContext): Promise<void> {
if (!this.rdbStore) {
this.rdbStore = await relationalStore.getRdbStore(context, DB_CONFIG);
// 创建用户表
await this.createUserTable();
// 创建商品表
await this.createProductTable();
// 创建购物车表
await this.createCartTable();
}
}
// 创建用户表
private async createUserTable(): Promise<void> {
const sql = ` CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
avatar TEXT,
nickname TEXT,
email TEXT,
phone TEXT,
gender INTEGER,
birthday TEXT
) `;
await this.rdbStore!.executeSql(sql);
}
// 创建商品表
private async createProductTable(): Promise<void> {
const sql = ` CREATE TABLE IF NOT EXISTS product (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
imageUrl TEXT,
price REAL,
originalPrice REAL,
sales INTEGER
) `;
await this.rdbStore!.executeSql(sql);
}
// 创建购物车表
private async createCartTable(): Promise<void> {
const sql = ` CREATE TABLE IF NOT EXISTS cart (
id INTEGER PRIMARY KEY AUTOINCREMENT,
productId INTEGER NOT NULL,
name TEXT NOT NULL,
imageUrl TEXT,
price REAL,
count INTEGER,
isChecked INTEGER
) `;
await this.rdbStore!.executeSql(sql);
}
// 查询数据
async query(sql: string, args?: Array<string>): Promise<Array<relationalStore.ResultSet>> {
if (!this.rdbStore) {
return [];
}
const resultSet = await this.rdbStore.querySql(sql, args);
const data: Array<relationalStore.ResultSet> = [];
if (resultSet.goToFirstRow()) {
do {
data.push(resultSet);
} while (resultSet.goToNextRow());
}
return data;
}
// 插入数据
async insert(tableName: string, values: Record<string, any>): Promise<number> {
if (!this.rdbStore) {
return -1;
}
const rowId = await this.rdbStore.insert(tableName, values);
return rowId;
}
// 更新数据
async update(tableName: string, values: Record<string, any>, whereClause?: string, whereArgs?: Array<string>): Promise<number> {
if (!this.rdbStore) {
return 0;
}
const count = await this.rdbStore.update(tableName, values, whereClause, whereArgs);
return count;
}
// 删除数据
async delete(tableName: string, whereClause?: string, whereArgs?: Array<string>): Promise<number> {
if (!this.rdbStore) {
return 0;
}
const count = await this.rdbStore.delete(tableName, whereClause, whereArgs);
return count;
}
}
2. SQLite 应用
修改 entry/src/main/ets/services/ProductService.ets:
import { HttpUtils } from '../utils/HttpUtils';
import { GoodsModel } from '../models/HomeModel';
import { SQLiteUtils } from '../utils/SQLiteUtils';
// 商品服务
export class ProductService {
// ... 其他方法
// 获取商品列表(先从本地数据库获取,再从网络获取)
async getProductList(): Promise<Array<GoodsModel>> {
// 先从本地数据库获取
const localData = await this.getProductListFromLocal();
if (localData.length > 0) {
return localData;
}
// 本地数据库无数据,从网络获取
const remoteData = await this.getProductListFromRemote();
// 将网络数据存入本地数据库
await this.saveProductListToLocal(remoteData);
return remoteData;
}
// 从本地数据库获取商品列表
private async getProductListFromLocal(): Promise<Array<GoodsModel>> {
const sql = 'SELECT * FROM product';
const resultSet = await SQLiteUtils.getInstance().query(sql);
const data: Array<GoodsModel> = [];
resultSet.forEach(row => {
data.push({
id: row.getDouble(row.getColumnIndex('id')),
name: row.getString(row.getColumnIndex('name')),
imageUrl: row.getString(row.getColumnIndex('imageUrl')),
price: row.getDouble(row.getColumnIndex('price')),
originalPrice: row.getDouble(row.getColumnIndex('originalPrice')),
sales: row.getDouble(row.getColumnIndex('sales'))
});
});
return data;
}
// 从网络获取商品列表
private async getProductListFromRemote(): Promise<Array<GoodsModel>> {
const response = await HttpUtils.getInstance().get<Array<GoodsModel>>('/api/products');
return response;
}
// 将商品列表存入本地数据库
private async saveProductListToLocal(data: Array<GoodsModel>): Promise<void> {
for (const item of data) {
await SQLiteUtils.getInstance().insert('product', {
id: item.id,
name: item.name,
imageUrl: item.imageUrl,
price: item.price,
originalPrice: item.originalPrice,
sales: item.sales
});
}
}
}
四、用户体验优化
4.1 加载动画
创建 entry/src/main/ets/components/LoadingComponent.ets:
@Component
export struct LoadingComponent {
@Prop isLoading: boolean = false;
build() {
Column({ space: 16 }) {
Progress({ value: 0, total: 100, type: ProgressType.ScaleRing })
.width(60)
.height(60)
.style({ strokeWidth: 5, scaleCount: 12, duration: 1000 });
Text('加载中...').fontSize(14).textColor('#666666');
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.visible(this.isLoading);
}
}
4.2 错误处理
创建 entry/src/main/ets/components/ErrorComponent.ets:
@Component
export struct ErrorComponent {
@Prop isError: boolean = false;
@Prop errorMessage: string = '请求失败';
onRetry: () => void;
build() {
Column({ space: 16 }) {
Image($r('app.media.error')).width(80).height(80).objectFit(ImageFit.Contain);
Text(this.errorMessage).fontSize(14).textColor('#666666');
Button('重试').width(120).height(48).backgroundColor('#007DFF').onClick(() => this.onRetry());
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.visible(this.isError);
}
}
五、项目运行与效果验证
5.1 项目配置
1. 配置 API 地址
在 entry/src/main/ets/utils/HttpUtils.ets 中替换为你的真实 API 地址:
const HTTP_CONFIG = {
baseUrl: 'https://your-api-address.com', // 替换为你的 API 地址
// ...
};
2. 初始化数据持久化
在 entry/src/main/ets/entryability/EntryAbility.ts 中初始化 Preferences 和 SQLite:
import { PreferencesUtils } from '../utils/PreferencesUtils';
import { SQLiteUtils } from '../utils/SQLiteUtils';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 初始化 Preferences
PreferencesUtils.getInstance().init(this.context);
// 初始化 SQLite
SQLiteUtils.getInstance().init(this.context);
}
// ...
}
5.2 项目运行
- 在 DevEco Studio 中点击「Run」按钮;
- 选择调试设备,点击「OK」;
- 等待编译安装完成,应用会自动在设备上启动。
效果验证:
- 商品列表网络请求:从真实 API 获取商品数据,支持本地缓存;
- 用户信息网络请求:实现用户登录、注册、个人信息查询;
- 网络状态检测:在无网络时显示网络状态提示;
- 加载动画:商品列表加载时显示环形进度条;
- 错误处理:请求失败时显示错误信息与重试按钮。

