网络管理开发
应用的开发离不开网络请求,因为我们不可能把所有数据都存储在本地,因此应用需要跟数据进行远程交互。而HarmonyOS也为开发者提供了网络管理模块,分别提供了以下功能:
- HTTP数据请求:通过HTTP发起一个数据请求
- WebSocket连接:使用WebSocket建立服务器与客户端的双向连接
- Socket:通过Socket进行数据传输
本文主要讲一下http请求的使用,其它具体请查阅官方文档
1 HTTP数据请求
1.1 HarmonyOS内置HTTP模块
1.1.1 使用示例
- 导入http模块
import http from "@oos.net.http"
- 使用http模块发送请求,处理响应
// 创建一个http的请求对象,不可复用
const httpRequest = http.createHttp()
// httpRequest.request(url, HttpRequestOptions)
// 发起网络请求
httpRequest.request(
"http://localhost:8080/users", // 请求URL路径
{
method: http.RequestMethod.GET,
extraData: {"param1": value1} // k1=v1&k2=v2
}
)
// 处理响应结果
.then((resp: http.HttpResponse) => {
if (resp.responseCode == 200) {
// 请求成功
}
})
.catch((err: Error) => {
// 请求失败
})
参数HttpRequestOptions具体参数属性
名称 | 类型 | 描述 |
---|---|---|
method | RequestMethod | 请求方式,GET、POST、PUT、DELETE等 |
extraData | string|Object | 请求参数 |
header | Object | 请求头字段 |
connectTimeout | number | 连接超时时间,单位毫秒,默认是60000ms |
readTimeout | number | 读取超时间,同上 |
请求返回结果HttpResponse具体属性值
名称 | 类型 | 描述 |
---|---|---|
responseCode | ResponseCode | 响应状态码 |
header | Object | 响应头 |
cookies | string | 响应返回的cookies |
result | string|Object | 响应体,默认是JSON字符串 |
resultType | HttpDataType | 返回值类型 |
1.2 第三方库:axios
因为axios属于第三方库,需要使用到HarmonyOS提供的第三方包管理工具:ohpm,具体查看官方文档
-
步骤1:下载和安装ohpm
- 下载ohpm工具包,下载链接
- 解压工具包,执行初始化命令
# windows 环境 init.bat # Linux或Mac环境 ./init.sh
- 将ohpm配置到环境变量
# windows 环境,直接在我的电脑配置即可 直接在系统变量的Path下加入你的ohpm安装路径即可, 如:D:\software\Huawei\command-line-tools\ohpm\bin # Linux或Mac环境,其中OHPM的路径请替换为ohpm的安装路径 export OHPM_HOME=/XX/ohpm export PATH=${OHPM_HOME}/bin:${PATH}
-
步骤2:下载和安装axios
- 下载axios
# 进入项目目录,然后使用命令行 ohpm install @ohos/axios
- 开放网络权限(涉及网络请求的都需要开发该权限)
{ "module": { "requestPermission": [ { "name": "ohos.permission.INTERNET" } ] } }
-
步骤3:使用axios (前端同学最熟悉了)
下面简单介绍一下axios的使用
导入axios
import axios from "@ohos/axios"
发送请求,并处理响应
axios.get(
'url',
{
params: { param1: 'value1' },
data: { param1: 'value1' }
}
)
.then(response => {
if (response.status !== 200) {
console.log('查询失败')
return false
}
console.log('查询成功')
})
.catch(err => {
console.log('查询失败', JSON.stringify(err))
})
2 数据持久化
2.1 用户首选项
- 导入首选项模块
import dataPreference from '@ohos.data.preferences'
- 获取首选项实例,读取指定文件
dataPreference.getPreferences(this.context, 'MyAppPreferences')
.then(peferences => {
// 获取成功
})
.catch(reason => {
// 获取失败
})
- 数据操作
// 写入数据,如果已经存在则会覆盖,可利用.has()判断是否存在
preferences.put('key', val)
.then(() => preferences.flush()) // 刷到磁盘
.catch(reason =>{}) // 处理异常
// 删除数据
preferences.delete('key')
.then(() => {}).catch(reason => {})
// 查询数据
preferences.get('key', 'defaultValue')
.then(value => console.log('查询成功'))
.catch(reason => console.log('查询失败'))
说明:
- Key为string类型,要求非空且长度不超过80字节
- Value可以是string、number、boolean及以上类型数组,大小不超过8192字节
- 数据量建议不超过一万条
使用示例:
- 创建preferences工具类:PreferencesUtil.ts
import preferences from '@ohos.data.preferences';
class PreferencesUtil {
// 存储preferences
prefs: Map<string, preferences.Preferences> = new Map()
// 初始化preferences
async initPreferences(context, name: string) {
try {
const pref = await preferences.getPreferences(context, name)
this.prefs.set(name, pref)
console.log('testTag', `preferences-${name} 初始化成功`)
} catch (e) {
console.log('testTag', `preferences-${name} 初始化失败:`, JSON.stringify(e))
}
}
// 写入数据
async putPreferences(name: string, key: string, value: preferences.ValueType) {
if (!this.prefs.has(name)) {
console.log(`testTag`, `preferences-${name} 不存在`)
return false
}
try {
const pref = this.prefs.get(name)
// 写入数据
await pref.put(key, value)
// 刷入磁盘
await pref.flush()
console.log('testTag', `preferences-${name} 数据写入成功`)
} catch (e) {
console.log('testTag', `preferences-${name} 数据写入失败:`, JSON.stringify(e))
}
}
// 查询数据
async getPreferences(name: string, key: string, defaultValue: preferences.ValueType) {
if (!this.prefs.has(name)) {
console.log(`testTag`, `preferences-${name} 不存在`)
return false
}
try {
const pref = this.prefs.get(name)
// 查询数据
const value = await pref.get(key, defaultValue)
console.log('testTag', `preferences-${name} 数据查询成功:`, value)
return value
} catch (e) {
console.log('testTag', `preferences-${name} 数据查询失败:`, JSON.stringify(e))
return ''
}
}
// 删除数据
async delPreferences(name: string, key:string) {
if (!this.prefs.has(name)) {
console.log(`testTag`, `preferences-${name} 不存在`)
return false
}
try {
const pref = this.prefs.get(name)
// 查询数据
await pref.delete(key)
console.log('testTag', `preferences-${name} 数据删除成功`)
} catch (e) {
console.log('testTag', `preferences-${name} 数据删除失败:`, JSON.stringify(e))
return ''
}
}
// 删除所有
async delAllPreferences(name: string | Array<string>, key:string) {
let nameList = []
if (name.length) {
// 数组
nameList = [...name]
} else {
nameList = [name]
}
const hasTag = nameList.filter(item => this.prefs.has(item))
if (!hasTag || (hasTag && hasTag.length === 0)) {
console.log(`testTag`, `preferences-${name} 不存在`)
return false
}
try {
nameList.forEach((item, index) => {
const pref = this.prefs.get(item)
pref.clear()
console.log('testTag', `preferences-${index}_${name} 全部删除成功`)
})
} catch (e) {
console.log('testTag', `preferences-${nameList} 删除失败:`, JSON.stringify(e))
return ''
}
}
}
const putils = new PreferencesUtil()
export default putils as PreferencesUtil
- 入口文件初始化preferences工具类
在入口文件EntryAbility.ts下添加如下代码
async onCreate(want, launchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
// 全局初始化
await PreferencesUtil.initPreferences(this.context, 'MyAppPreferences');
// 如果有多个可以继续初始化
// await PreferencesUtil.initPreferences(this.context, 'MyOrderPreferences');
}
- 使用例子,这里用的是父子组件,一般都是全局跨组件的才会使用持久化数据,建议使用@Provide/@Consume传递参数值,这里就简单操作了,使用@Prop
//Index组件(父组件)
import PreferencesUtil from '../utils/PreferencesUtil'
@Entry
@Component
struct Index {
@State fontSize: number = 16
build() {
Row() {
Column() {
DemoBuilder({ fontSize: this.fontSize })
Row() {
Button("字体20")
.width(100)
.height(40)
.fontSize(18)
.fontColor(Color.White)
.backgroundColor(Color.Blue)
.margin(10)
.onClick(async () => {
this.fontSize = 22
await PreferencesUtil.putPreferences("MyAppPreferences", "fontSize", 22)
console.log('添加成功')
})
Button("字体30")
.width(100)
.height(40)
.fontSize(18)
.fontColor(Color.White)
.backgroundColor(Color.Blue)
.margin(10)
.onClick(async () => {
this.fontSize = 30
await PreferencesUtil.putPreferences("MyAppPreferences", "fontSize", 30)
console.log('添加成功30')
})
}.margin({top: 30})
}
}
.height('100%')
}
}
// 子组件
import PreferencesUtil from '../../utils/PreferencesUtil'
@Component
export struct DemoBuilder {
@Prop fontSize: number
// 自定义构建函数
@Builder showRepeatCode() {
Text("重复UI调用")
.fontColor(Color.Red)
.fontSize(this.fontSize)
}
async aboutToAppear() {
this.fontSize = await PreferencesUtil.getPreferences("MyAppPreferences","fontSize",16) as number
}
build() {
Column() {
this.showRepeatCode()
Text("测试字体大小")
.fontColor(Color.Blue)
.fontSize(this.fontSize)
.margin({top: 30})
// myGlobalBuilder()
}
}
}
2.2 关系型数据库
关系型数据库(RDB)是基于SQLite组件提供的本地数据库,用于管理应用中的结构化数据。例如:记账本、备忘录
-
步骤1:初始化数据库
- 导入关系型数据库模块
import relationalStore from '@ohos.data.relationalStore'
- 初始化数据库表
// rdb配置 const config = { name: 'MyApplication.db', // 数据库文件名 securityLevel: relationalStore.SecurityLevel.S1 // 数据库安全级别 } // 初始化表的SQL const sql = `CREATE TABLE IF NOT EXISTS TASK ( ID INTEGER PRIMARY KEY, NAME TEXT NOT NULL, FINISHED bit )` // 获取rdb relationalStore.getRdbStore(this.context, config, (err, rdbStore) => { // 执行sql,后续的所有增删改查都是使用rdbStore对象 rdbStore.executeSql(sql) })
-
步骤2:增、删、改、查数据
- 新增数据
// 准备数据 const task = { id: 1, name: '测试1', finished: false } // 新增 this.rdbStore.insert(this.tableName, task)
- 修改
// 要更新的数据 const task = { finished: true } // 查询条件,RdbPredicates就是条件谓词 const predicates = new relationalStore.RdbPredicates(this.tableName) predicates.equalTo('ID', id) // 执行更新 this.rdbStore.update(task, predicates)
- 删除
// 查询条件 const predicates = new relationalStore.RdbPredicates(this.tableName) predicates.equalTo('ID', id) // 执行删除 this.rbdStore.delete(predicates)
- 查询数据
// 查询条件 const predicates = new relationalStore.RdbPredicates(this.tableName) // 执行查询 ['ID', 'NAME', 'FINISHED'] => 需要查询的字段 const result = await this.rdbStore.query(predicates, ['ID', 'NAME', 'FINISHED']) // 解析结果 (接触过数据库都知道,查询数据一般返回的是一个结果集) // 准备数据保存结果 let tasks: any[] = [] // 循环遍历结果集,判断是否遍历到最后一行 while(!result.isAtLastRow) { // 指针移动到下一行数据 result.goToNextRow() // 根据字段名获取字段index,从而获取字段值 const id = result.getLong(result.getColumnIndex("ID")) const name = result.getString(result.getColumnIndex("NAME")) tasks.push({id, name}) }
关系数据库使用示例:
// 创建TaskModel.ets
/**
* 这里为什么创建.ets文件?
* 原因:如果是创建ts文件,那么就不能使用ArkTs的状态管理,所需要创建为.ets文件
* 另外,项目初始化时,如果入口文件EntryAbility文件如果是.ts,则需要改为.ets文件** ,因为.ts文件不能导入.ets文件
*/
import relationalStore from '@ohos.data.relationalStore';
/**
* 说明:如果是跨组件使用TaskModel,那么需要加上@Observed进行属性观察,
* 本例子所有代码都在当前组件写了,所以就不添加@Observed了
*/
// @Observed
class TaskModel {
// 存储rdbStore
private rdbStore: relationalStore.RdbStore
// 表名
private tableName: string = 'TASK' // 这里写死了,后续优化可以抽取为参数传值
/**
* 初始化数据表
* @param context
*/
async initTaskModel(context) {
// rdb 配置
const config = {
name: 'MyApplication.db',
securityLevel: relationalStore.SecurityLevel.S1
}
// 初始化数据表
const sql = `CREATE TABLE IF NOT EXISTS TASK (
ID INTEGER PRIMARY KEY,
NAME TEXT NOT NULL,
FINISHED bit
)`
try {
// 获取rdb
const rdbStore = await relationalStore.getRdbStore(context, config)
// 执行SQL
rdbStore.executeSql(sql)
this.rdbStore = rdbStore
} catch (e) {
console.log('testTag', '获取rdbStore失败', JSON.stringify(e))
}
}
/**
* 查询task列表数据
* 注:这里后续有需要可以抽取成公用方法,有点麻烦,先简单写,嘿嘿
*/
async getTaskList() {
// 查询条件
const predicates = new relationalStore.RdbPredicates(this.tableName)
// 执行查询
const result = await this.rdbStore.query(predicates, ['ID', 'NAME', 'FINISHED'])
// 解析结果 (接触过数据库都知道,查询数据一般返回的是一个结果集)
// 准备数据保存结果
let tasks: any[] = []
// 循环遍历结果集,判断是否遍历到最后一行
while(!result.isAtLastRow) {
// 指针移动到下一行数据
result.goToNextRow()
// 根据字段名获取字段index,从而获取字段值
const id = result.getLong(result.getColumnIndex("ID"))
const name = result.getString(result.getColumnIndex("NAME"))
const finished = result.getLong(result.getColumnIndex("FINISHED"))
tasks.push({id, name, finished})
}
console.log('testTag', '数据查询成功', JSON.stringify(tasks))
return tasks
}
/**
* 删除任务
* @param id
* @returns
*/
delTask(id: number): Promise<number> {
// 查询条件
const predicates = new relationalStore.RdbPredicates(this.tableName)
predicates.equalTo('ID', id)
// 执行删除
return this.rdbStore.delete(predicates)
}
/**
* 更新任务列表
* @param id
* @param finished
* @returns
*/
updateTask(id: number, finished: boolean): Promise<number> {
// 更新的数据
const data = { finished }
// 查询条件
const predicates = new relationalStore.RdbPredicates(this.tableName)
predicates.equalTo('ID', id)
// 执行删除
return this.rdbStore.update(data, predicates)
}
/**
* 添加任务
* @param name
* @param finished
* @returns
*/
addTask(name: string, finished: boolean): Promise<number> {
// 新增
return this.rdbStore.insert(this.tableName, { name, finished })
}
}
const model = new TaskModel()
export default model as TaskModel
初始化TaskModel
// EntryAbility.ets文件加入如下代码
async onCreate(want, launchParam) {
...
// 初始化数据表
await TaskModel.initTaskModel(this.context)
}
使用TaskModel
import TaskModel from '../model/TaskModel'
@Entry
@Component
struct Index {
@State taskName: string = ''
@State taskList: any[] = []
async aboutToAppear() {
this.handleRefreshList()
}
async handleRefreshList() {
this.taskList = await TaskModel.getTaskList()
}
@Builder delButton($$: { id: number }) {
Button('删除')
.fontSize(18)
.fontColor(Color.White)
.backgroundColor(Color.Red)
.margin({ left: 15 })
.onClick(async () => {
await TaskModel.delTask($$.id)
this.handleRefreshList()
})
}
build() {
Row() {
Column() {
Row() {
TextInput({ placeholder: '请输入任务名称', text: this.taskName })
.fontSize(20)
.width(300)
.onChange(val => {
this.taskName = val
})
Button("添加")
.height(40)
.fontSize(20)
.fontColor(Color.White)
.backgroundColor(Color.Blue)
.layoutWeight(1)
.margin({left: 10})
.onClick(async () => {
await TaskModel.addTask(this.taskName, false)
this.handleRefreshList()
// 清空输入框
this.taskName = ''
})
}.margin({bottom: 20})
.justifyContent(FlexAlign.SpaceBetween)
// 渲染列表
List({ space: 10 }) {
ForEach(this.taskList, (item, index) => {
ListItem() {
Row() {
Text(item.name)
.fontSize(24)
.fontColor("#ff6602")
.fontWeight(FontWeight.Bold)
Checkbox()
.select(!!item.finished)
.selectedColor("#ff6602")
.onChange(async (value) => {
await TaskModel.updateTask(item.id, value)
// 这里可以重新请求一次查询数据,也可以不加
})
}
.width("90%")
.borderWidth(1)
.borderColor("#dddddd")
.padding(10)
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({
end: this.delButton({ id: item.id })
})
})
}
.alignListItem(ListItemAlign.Center)
}
.justifyContent(FlexAlign.Start)
.height("100%")
}
.height('100%')
}
}
效果图:
总结
本文主要是对HarmonyOS的HTTP网络请求做了简单的了解,以及对数据持久化的使用示例,如有不足之处,请指正,谢谢查阅!!