云计算百科
云计算领域专业知识百科平台

鸿蒙APP开发从入门到精通:网络请求与数据持久化

《鸿蒙APP开发从入门到精通》第4篇:网络请求与数据持久化 🗄️

在这里插入图片描述


内容承接与核心价值

这是《鸿蒙APP开发从入门到精通》的第4篇——数据基础篇,承接第3篇的「自定义组件与数据双向绑定」,100%复用项目架构,为后续第6-12篇的电商购物车全栈项目铺垫网络数据获取和本地数据持久化的核心技术。

学习目标:

  • 掌握鸿蒙官方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 实战目标

基于第3篇的「MyFirstHarmonyApp」项目架构,实现以下功能:

  • 商品列表网络请求:从真实API获取商品数据,替换模拟数据;
  • 用户信息网络请求:实现用户登录、注册、个人信息查询;
  • 网络请求拦截器:实现请求拦截与响应拦截;
  • 网络状态检测:检测网络连接状态,优化用户体验。

2.2 🔧 业务服务实现

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.3 🔧 网络状态检测

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提供了3种数据持久化方式:

方式功能适用场景
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获取商品数据,支持本地缓存; ✅ 用户信息网络请求:实现用户登录、注册、个人信息查询; ✅ 网络状态检测:在无网络时显示网络状态提示; ✅ 加载动画:商品列表加载时显示环形进度条; ✅ 错误处理:请求失败时显示错误信息与重试按钮。


六、 总结与未来学习路径 🚀

6.1 总结

本文作为《鸿蒙APP开发从入门到精通》的第4篇,完成了:

  • 鸿蒙官方HTTP请求库的配置与使用;
  • 商品列表与用户信息的网络请求实现;
  • Preferences与SQLite数据持久化的应用;
  • 网络请求拦截器、网络状态检测、加载动画、错误处理等用户体验优化。

6.2 未来学习路径

  • 第5篇:页面路由与组件跳转;
  • 第6篇:原子化服务与元服务卡片的开发;
  • 第7篇:超级终端多设备协同开发;
  • 第8篇:服务联邦跨服务无缝打通;
  • 第9篇:安全加固与组件化架构;
  • 第10篇:AI原生与用户增长;
  • 第11篇:性能优化与Next原生合规;
  • 第12篇:运维监控、生态运营与专属变现。

结语 ✅

恭喜你!你已经完成了《鸿蒙APP开发从入门到精通》的第4篇,掌握了网络请求与数据持久化的核心技术。

从现在开始,你已具备了与后端API交互和本地数据存储的能力。未来的8篇文章将逐步构建一个完整的鸿蒙电商购物车全栈项目,并最终实现华为应用市场上架变现。

让我们一起期待鸿蒙生态的爆发! 🎉🎉🎉

赞(0)
未经允许不得转载:网硕互联帮助中心 » 鸿蒙APP开发从入门到精通:网络请求与数据持久化
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!