文章目录
- 本文是eTS DataAbility样例实践,主要展示了eTS FA使用 eTS DataAbility实现图书信息的管理功能,包括 rdb数据库的创建,数据的增删改查,批量操作等。是继 ServiceAbility 的第二篇。 Ability是HarmonyOS应用程序的重要组成部分,分为FA(Feature Ability)和PA(Particle Ability)两种类型。PA有 Service Ability和Data Ability,Service Ability模板用于提供后台运行任务的能力;Data Ability模板用于对外部提供统一的数据访问抽象。 Gitee 样例地址: https://gitee.com/openharmony/app_samples/tree/master/ability/DataAbility。 大家也可以自行下载运行,但需要OpenHarmony的设备才能运行。 先来展示一下效果:
- 项目结构图:
└─main │ config.json │ ├─ets │ ├─DataAbility │ │ data.ts │ │ │ └─MainAbility │ │ app.ets │ │ │ ├─component │ │ bookView.ets │ │ searchBar.ets │ │ titleBar.ets │ │ │ ├─model │ │ BookDataModel.ts │ │ DaHelperConst.ts │ │ │ └─pages │ index.ets │ query.ets │ update.ets │ └─resources
-
- 创建一个BookModel 数据模型,定义一些属性字段 ,一个编号、一个名称、一个介绍。 export class BookModel { id: number name: string introduction: string constructor(id: number, name: string, introduction: string) { this.id = id this.name = name this.introduction = introduction }} 还是在这个ts文件中,再编写一些方便展示的初始化测试数据的函数,export出去就可以直接调用了。这个地方需要注意的是自增ID不要写 。 //初始化测试数据export function initValuesBuckets() { let valuesBuckets = [ { 'name': 'Book name1', 'introduction': 'Book introduction1' }, { 'name': 'Book name2', 'introduction': 'Book introduction2' }, { 'name': 'Book name3', 'introduction': 'Book introduction3' }] return valuesBuckets} 再编写一个将resultSet数据转换位BookModel 数组的函数,用于处理DA_HELPER返回的数据。 //获取一个BookModel 的数据列表export function getListFromResultSet(resultSet) { console.info(TAG + ' getListFromResultSet') let bookList = [] console.log(TAG + ' resultSet column names:' + resultSet.columnNames) console.log(TAG + ' resultSet row count:' + resultSet.rowCount) console.log(TAG + ' resultSet goToFirstRow:' + resultSet.goToFirstRow()) for (let i = 0;i < resultSet.rowCount; i++) { //按照构造函数进行封装 let book = new BookModel( resultSet.getDouble(resultSet.getColumnIndex('id')) , resultSet.getString(resultSet.getColumnIndex('name')) , resultSet.getString(resultSet.getColumnIndex('introduction'))) //添加到列表中 bookList.push(book) console.log(TAG + ' resultSet book:' + JSON.stringify(book)) console.log(TAG + ' resultSet goToNextRow:' + resultSet.goToNextRow()) } return bookList}
- 定义一个DaHelperConst.ts 常量类,用于存储数据库常用属性。 首先引入FA访问类 //引入FA访问类import featureAbility from '@ohos.ability.featureAbility' 定义数据访问URI、表列名、DataAbility帮助类 等常量 //定义 数据访问URI 常量export const BASE_URI = 'dataability:///ohos.samples.etsdataability.DataAbility'//定义 表的列名export const COLUMNS = ['id', 'name', 'introduction']//获取一个DataAbility的帮助类export const DA_HELPER = featureAbility.acquireDataAbilityHelper(BASE_URI)
- 视图组件,实现了一个图书展示的列表效果。 //引入 BookDataModel 数据模块import { BookModel } from '../model/BookDataModel' 定义 book数据模型对象、删除数据的回调函数。 @Componentexport struct BookView { //定义 book数据模型对象 private book: BookModel = null //定义 删除数据的回调函数 private deleteCallback = null 构建视图显示: build() { Row() { //一张图片 Image($r('app.media.book')) .height(110).width(80) .objectFit(ImageFit.Cover) .margin({ top: 5, bottom: 5 }) //垂直方向的两行文本 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) { Text(this.book.name) .fontColor(Color.Black) .fontSize(22) .fontWeight(FontWeight.Bold) Text(this.book.introduction) .fontColor(Color.Grey) .fontSize(20) .margin({ top: 10 }) } .layoutWeight(1) .margin({ left: 5 }) //删除数据的按钮 if (this.deleteCallback !== null) { Button() { Image($r('app.media.delete_red')) .height(35).width(35) .objectFit(ImageFit.Contain) } .type(ButtonType.Circle) .height(50).width(50) .backgroundColor('#F5F5F5') .onClick(() => { this.deleteCallback(this.book) }) } } .width('100%') .padding({ left: 15, right: 15 }) }} 效果图:
- 视图组件,实现了一个搜索栏的效果,使用了Stack 布局,让放大镜能叠加在文本输入框上。 用Text 模拟TextInput 效果,点击进行跳转到搜索界面。 //引用路由,用于跳转界面import router from '@ohos.router'@Preview@Componentexport struct SearchBar { build() { Stack({ alignContent: Alignment.End }) { //模拟TextInput的文本 Text($r('app.string.search_tip')) .height('80%').width('94%') .fontSize(16) .padding({ left: 15 }) .margin('3%') .backgroundColor('#A5A5A5') .border({ radius: 20 }) //放大镜icon Image($r('app.media.search_gray')) .height(40).width(40) .margin({ right: '5%' }) .objectFit(ImageFit.Contain) } .height(50).width('100%') .backgroundColor('#F5F5F5') .onClick(() => { router.push({ url: 'pages/Query' }) }) }} 效果图:
- 视图组件,实现了一个顶部标题栏的效果,提供了一个批量插入数据的操作按钮。 组件内定义回调函数的声明,在具体使用组件的界面在对回调函数进行实现,可以学习这种设计组件的方法。 @Componentexport struct TitleBar { //定义 批量插入的回调函数 private batchInsertCallback = null build() { Row() { //标题名称 Text($r('app.string.title')) .fontColor(Color.White) .fontSize(20) .layoutWeight(1) //批量插入 操作按钮 Button() { Text($r('app.string.batch_insert')) .fontColor(Color.White) .fontSize(22) .textAlign(TextAlign.End) } .type(ButtonType.Normal) .height('100%') .backgroundColor('#0D9FFB') .onClick(() => { this.batchInsertCallback() }) } .height('8%').width('100%') .backgroundColor('#0D9FFB') .padding({ left: 15, right: 15 }) }}
- index.ets是和用户完成交互的主要页面。 需要引入数据访问能力类、路由,前面定义的常量类、视图组件、数据模块类等。 //引入数据访问能力类import dataAbility from '@ohos.data.dataAbility'//引入路由,实现跳转界面import router from '@ohos.router'//引入定义的常量、视图组件import { BASE_URI, COLUMNS, DA_HELPER } from '../model/DaHelperConst'import { BookView } from '../component/BookView'import { TitleBar } from '../component/TitleBar'import { SearchBar } from '../component/SearchBar'//引入数据模块类import { BookModel, initValuesBuckets, getListFromResultSet } from '../model/BookDataModel' 通过DA_HELPER查询数据实现页面显示图书列表效果,实现删除和批量插入数据的效果。 @Entry@Componentstruct Index { @State bookList: Array<BookModel> = [] //生命周期回调,自动执行,页面显示前 //页面显示时触发一次,包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。 onPageShow() { this.queryAll() } queryAll = () => { console.info(TAG + ' queryAll') //获取谓词 let predicates = new dataAbility.DataAbilityPredicates() //使用DA_HELPER 查询数据 DA_HELPER.query(BASE_URI, COLUMNS, predicates, (err, resultSet) => { //重新封装查询结果 this.bookList = getListFromResultSet(resultSet) }) } deleteCallback = (book) => { let predicates = new dataAbility.DataAbilityPredicates() predicates.equalTo('id', book.id) //使用DA_HELPER 删除数据 DA_HELPER.delete(BASE_URI, predicates, (err, num) => { console.info(TAG + ' delete num=' + num) this.queryAll() }) } batchInsertCallback = () => { let valuesBuckets = initValuesBuckets() //使用DA_HELPER 批量插入数据 DA_HELPER.batchInsert(BASE_URI, valuesBuckets, (err, num) => { console.info(TAG + ' batch insert num=' + num) this.queryAll() }) } build代码块,实现了列表显示的效果,使用了Stack布局,List等组件。 点击行,跳转到更新数据界面,传递book对象过去,注意跳转的路由要在config.json配置好。 build() { Column() { //标题栏 TitleBar({ batchInsertCallback: this.batchInsertCallback }) //搜索栏 SearchBar() //列表 Stack({ alignContent: Alignment.BottomEnd }) { //列表显示 List() { ForEach(this.bookList, item => { ListItem() { BookView({ book: item, deleteCallback: this.deleteCallback }) } .onClick(() => { //点击行,跳转到更新数据界面,传递book对象过去 router.push({ url: 'pages/Update', params: { book: item } }) }) }, item => JSON.stringify(item)) } .width('100%') .margin({ bottom: 100 }) .constraintSize({ minHeight: '100%' }) .divider({ strokeWidth: 1, color: Color.Gray, startMargin: 10, endMargin: 10 }) //添加单条数据按钮 Button() { Image($r('app.media.add')) } .type(ButtonType.Circle) .width(60) .height(60) .backgroundColor('#0D9FFB') .margin({ bottom: 150, right: 50 }) .onClick(() => { console.info(TAG + ' insert onClick') let valuesBuckets = { name: 'Book name', introduction: 'Book introduction' } DA_HELPER.insert(BASE_URI, valuesBuckets, (err, num) => { console.info(TAG + ' insert num=' + num) this.bookList.push({ id: num, name: 'Book name', introduction: 'Book introduction' }) }) }) } .width('100%').height('100%') } .width('100%').height('100%')} 效果图:
- 引入依赖和index.ets类似: import router from '@ohos.router';import dataAbility from '@ohos.data.dataAbility'import { BASE_URI, COLUMNS, DA_HELPER } from '../model/DaHelperConst'import { BookModel, getListFromResultSet } from '../model/BookDataModel'import { BookView } from '../component/BookView' 查询数据: //查询数据query(queryStr) { let predicates = new dataAbility.DataAbilityPredicates() //根据名字或介绍模糊匹配 predicates.contains('name', queryStr) .or() .contains('introduction', queryStr) DA_HELPER.query(BASE_URI, COLUMNS, predicates, (err, resultSet) => { this.bookList = getListFromResultSet(resultSet) })} 列表显示,和index.ets 类似,没有了删除按钮。 使用了ForEach、Stack、 TextInput 等组件, TextInput组件的onChange事件触发查询。 build() { Column() { Row() { Image($r('app.media.ic_back')) .width(40).height(40) .objectFit(ImageFit.Contain) .onClick(() => { router.back() }) Text($r('app.string.title')) .fontColor(Color.White) .fontSize(20) .layoutWeight(1) } .height(50).width('100%') .backgroundColor('#0D9FFB') .padding({ left: 10, right: 10 }) Stack({ alignContent: Alignment.End }) { TextInput({ placeholder: $r('app.string.search_placeholder')}) .height('85%').width('94%') .padding({ left: 15 }) .margin('3%') .backgroundColor('#F0F0F0') .border({ radius: 20 }) //触发查询 .onChange((value: string) => { console.info(TAG + ' query str=' + value) if (value !== '') { this.query(value) }else{ this.bookList = [] } }) Image($r('app.media.search_gray')) .height(40).width(40) .margin({ right: '5%' }) .objectFit(ImageFit.Contain) } .width('100%').height(50) .backgroundColor('#F5F5F5') List() { ForEach(this.bookList, item => { ListItem() { BookView({ book: item, deleteCallback: null }) } .onClick(() => { router.push({ url: 'pages/update', params: { book: item } }) }) }, item => JSON.stringify(item)) } .width('100%') .layoutWeight(1) .divider({ strokeWidth: 1, color: Color.Gray, startMargin: 10, endMargin: 10 }) }} 复制
- 引入依赖: //引入依赖import router from '@ohos.router';import prompt from '@system.prompt';import dataAbility from '@ohos.data.dataAbility'import { BASE_URI, DA_HELPER } from '../model/DaHelperConst'import { BookModel } from '../model/BookDataModel' 声明BookModel的变量,从router中接收携带的参数book对象,用于原信息的显示。 @Entry@Componentstruct Update { //从router中接收携带的参数book对象,用于原信息的显示 private book: BookModel = <BookModel> router.getParams()["book"] 使用DA_HELPER 更新数据,更新完返回列表界面。 updateBook = () => { let predicates = new dataAbility.DataAbilityPredicates() predicates.equalTo('id', this.book.id) let valuesBucket = { 'name': this.book.name, 'introduction': this.book.introduction } DA_HELPER.update(BASE_URI, valuesBucket, predicates, (err, num) => { console.info(TAG + ' update book num=' + num) router.back() })} 显示要修改的图书信息,支持修改,支持返回、提交修改按钮。 使用了Scroll、Image、Text、TextInput等组件。 build() { Column() { Row() { //返回按钮 Image($r('app.media.ic_back')) .width(40).height(40) .objectFit(ImageFit.Contain) .onClick(() => { router.back() }) //标题 Text($r('app.string.title')) .fontColor(Color.White) .fontSize(20) .layoutWeight(1) //提交修改按钮 Image($r('app.media.submit')) .width(50).height(50) .objectFit(ImageFit.Contain) .onClick(() => { console.info(TAG + ' update onClick,title=' + this.book.name) if (this.book.name === '' || this.book.introduction === '') { prompt.showToast({ message: 'Please input name or introduction' }) return } this.updateBook() }) } .height(50).width('100%') .backgroundColor('#0D9FFB') .padding({ left: 10, right: 10 }) //显示要修改的信息,支持滚动条 Scroll() { Column() { Image($r('app.media.book')) .width(120).height(150) .objectFit(ImageFit.Fill) .margin(5) Text($r('app.string.book_name')) .fontWeight(FontWeight.Bold) .fontSize(22) .width('100%') .margin({ top: 20 }) .fontColor(Color.Black) TextInput({ placeholder: 'input name', text: this.book.name }) .type(InputType.Normal) .placeholderColor(Color.Gray) .fontSize(19) .margin({ top: 10 }) //修改信息后更新book对象 .onChange((value: string) => { this.book.name = value }) Text($r('app.string.book_intro')) .fontWeight(FontWeight.Bold) .fontSize(22) .width('100%') .fontColor(Color.Black) .margin({ top: 20 }) TextInput({ placeholder: 'input introduction', text: this.book.introduction }) .type(InputType.Normal) .placeholderColor(Color.Gray) .fontSize(19) .margin({ right: 10, top: 10 }) //修改信息后更新book对象 .onChange((value: string) => { this.book.introduction = value }) } .width('100%') .constraintSize({ minHeight: '100%' }) .padding(15) }.height('100%') }}
- 1、我们发现并没有调用 DataAbility 的代码,那DataAbility 怎么被跑起来的呢? 其实是 DataAbility 是会被自动运行的,只要在config.json 中做了配置,当应用启动后,DataAbility就会被自动运行,在DataAbility完成初始化后,会调用声明周期回调函数 onInitialized,完成数据库的初始化。 看一下 DataAbility 在config.json 中的配置: "abilities": [{ "visible": true, "srcPath": "DataAbility", "name": ".DataAbility", "icon": "$media:icon", "srcLanguage": "ets", "description": "$string:description_dataability", "type": "data", "uri": "dataability://ohos.samples.etsdataability.DataAbility"} 启动应用,从日志输出中我们可以看到 DataAbility 被运行。 05-17 23:00:11.016 526-1367/foundation I 01110/AppMgrService: [module_running_record.cpp(LaunchAbility:178)]ScheduleLaunchAbility ability:ohos.samples.etsdataability.DataAbility 那DataAbility 数据的增删改查,也没有看到调用的代码呢? 代码里只是用了DA_HELPER对象来操作数据,并没有调用DataAbility/data.ts 的 insert/batchInsert/query/update/delete 这些函数, 其实是 DA_HELPER 在初始化时 绑定的 BASE_URI(如下) 和 config.json文件中 DataAbility 的uri 是一致的,可以看上面config.json 的配置中uri的值。 (注意 config.json中的 uri 只能是 “dataablity://xxxxxxxxx” ,两道杠 )。 //定义 数据访问URI 常量export const BASE_URI = 'dataability:///ohos.samples.etsdataability.DataAbility'//获取一个DataAbility的帮助类export const DA_HELPER = featureAbility.acquireDataAbilityHelper(BASE_URI) 有关BASE_URI格式说明参见下图,更详尽的参考。 2、DataAbility/data.ts 中创表语句中的表名,注意要和TABLE_NAME常量保持一致,否则数据无法插入成功。

本文是eTS DataAbility样例实践,主要展示了eTS FA使用 eTS DataAbility实现图书信息的管理功能,包括 rdb数据库的创建,数据的增删改查,批量操作等。是继 ServiceAbility 的第二篇。
Ability是HarmonyOS应用程序的重要组成部分,分为FA(Feature Ability)和PA(Particle Ability)两种类型。PA有 Service Ability和Data Ability,Service Ability模板用于提供后台运行任务的能力;Data Ability模板用于对外部提供统一的数据访问抽象。
Gitee 样例地址:
https://gitee.com/openharmony/app_samples/tree/master/ability/DataAbility。
大家也可以自行下载运行,但需要OpenHarmony的设备才能运行。
先来展示一下效果:

项目结构图:
└─main
│ config.json
│
├─ets
│ ├─DataAbility
│ │ data.ts
│ │
│ └─MainAbility
│ │ app.ets
│ │
│ ├─component
│ │ bookView.ets
│ │ searchBar.ets
│ │ titleBar.ets
│ │
│ ├─model
│ │ BookDataModel.ts
│ │ DaHelperConst.ts
│ │
│ └─pages
│ index.ets
│ query.ets
│ update.ets
│
└─resources
创建一个DataAbility很简单,就是File—New ----Ability—DataAbility,起个名字,
你可以按照数据类型命名,例如:GoodsDataAbility一个用来存储商品的DataAbility,需要注意的是,你命名的其实是个目录或者叫做路径,这个路径指向一个叫data.ts的文件,相应的代码编写也是在这个data.ts的文件。
一起来看一下实现一个DataAbility都需要做哪些事,
引入依赖:
//引入数据访问类
import dataAbility from '@ohos.data.dataAbility'
//引入rdb库
import dataRdb from '@ohos.data.rdb'
定义 rdb库对象、库配置、表名、创表SQL 等变量。
//rdb库对象
let rdbStore: dataRdb.RdbStore = undefined
//库的配置信息:库名称
const STORE_CONFIG = { name: 'book.db' }
//表名
const TABLE_NAME = 'book'
//表结构
const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS book(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, introduction TEXT NOT NULL)'
接下来是功能函数的实现,这部分完全可以直接复用。
初始化库和表:
//初始化库和表
onInitialized(abilityInfo) {
console.info(`${TAG} DataAbility onInitialized`)
console.log(`${TAG} create table begin`)
dataRdb.getRdbStore(abilityInfo, STORE_CONFIG, 1)
.then((rdb) => {
console.log(`${TAG} create table done`)
rdb.executeSql(SQL_CREATE_TABLE)
rdbStore = rdb
console.log(`${TAG} create table end`)
})
.catch((error) => {
console.log(`${TAG} create table err = ${JSON.stringify(err)}`)
})
},
增删改查 数据操作:
//增删改查 数据操作
insert(uri, valueBucket, callback) {
console.info(TAG + ' insert start')
rdbStore.insert(TABLE_NAME, valueBucket, callback)
},
batchInsert(uri, valueBuckets, callback) {
console.info(TAG + ' batch insert start')
for (let i = 0;i < valueBuckets.length; i++) {
console.info(TAG + ' batch insert i=' + i)
if (i < valueBuckets.length - 1) {
rdbStore.insert(TABLE_NAME, valueBuckets[i], (err: any, num: number) => {
console.info(TAG + ' batch insert ret=' + num)
})
} else {
rdbStore.insert(TABLE_NAME, valueBuckets[i], callback)
}
}
},
query(uri, columns, predicates, callback) {
console.info(TAG + ' query start')
let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates)
rdbStore.query(rdbPredicates, columns, callback)
},
update(uri, valueBucket, predicates, callback) {
console.info(TAG + 'update start')
let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates)
rdbStore.update(valueBucket, rdbPredicates, callback)
},
delete(uri, predicates, callback) {
console.info(TAG + 'delete start')
let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates)
rdbStore.delete(rdbPredicates, callback)
}
创建一个BookModel 数据模型,定义一些属性字段 ,一个编号、一个名称、一个介绍。
export class BookModel {
id: number
name: string
introduction: string
constructor(id: number, name: string, introduction: string) {
this.id = id
this.name = name
this.introduction = introduction
}
}
还是在这个ts文件中,再编写一些方便展示的初始化测试数据的函数,export出去就可以直接调用了。这个地方需要注意的是自增ID不要写 。
//初始化测试数据
export function initValuesBuckets() {
let valuesBuckets = [
{ 'name': 'Book name1', 'introduction': 'Book introduction1' },
{ 'name': 'Book name2', 'introduction': 'Book introduction2' },
{ 'name': 'Book name3', 'introduction': 'Book introduction3' }]
return valuesBuckets
}
再编写一个将resultSet数据转换位BookModel 数组的函数,用于处理DA_HELPER返回的数据。
//获取一个BookModel 的数据列表
export function getListFromResultSet(resultSet) {
console.info(TAG + ' getListFromResultSet')
let bookList = []
console.log(TAG + ' resultSet column names:' + resultSet.columnNames)
console.log(TAG + ' resultSet row count:' + resultSet.rowCount)
console.log(TAG + ' resultSet goToFirstRow:' + resultSet.goToFirstRow())
for (let i = 0;i < resultSet.rowCount; i++) {
//按照构造函数进行封装
let book = new BookModel(
resultSet.getDouble(resultSet.getColumnIndex('id'))
, resultSet.getString(resultSet.getColumnIndex('name'))
, resultSet.getString(resultSet.getColumnIndex('introduction')))
//添加到列表中
bookList.push(book)
console.log(TAG + ' resultSet book:' + JSON.stringify(book))
console.log(TAG + ' resultSet goToNextRow:' + resultSet.goToNextRow())
}
return bookList
}
定义一个DaHelperConst.ts 常量类,用于存储数据库常用属性。
首先引入FA访问类
//引入FA访问类
import featureAbility from '@ohos.ability.featureAbility'
定义数据访问URI、表列名、DataAbility帮助类 等常量
//定义 数据访问URI 常量
export const BASE_URI = 'dataability:///ohos.samples.etsdataability.DataAbility'
//定义 表的列名
export const COLUMNS = ['id', 'name', 'introduction']
//获取一个DataAbility的帮助类
export const DA_HELPER = featureAbility.acquireDataAbilityHelper(BASE_URI)
视图组件,实现了一个图书展示的列表效果。
//引入 BookDataModel 数据模块
import { BookModel } from '../model/BookDataModel'
定义 book数据模型对象、删除数据的回调函数。
@Component
export struct BookView {
//定义 book数据模型对象
private book: BookModel = null
//定义 删除数据的回调函数
private deleteCallback = null
构建视图显示:
build() {
Row() {
//一张图片
Image($r('app.media.book'))
.height(110).width(80)
.objectFit(ImageFit.Cover)
.margin({ top: 5, bottom: 5 })
//垂直方向的两行文本
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) {
Text(this.book.name)
.fontColor(Color.Black)
.fontSize(22)
.fontWeight(FontWeight.Bold)
Text(this.book.introduction)
.fontColor(Color.Grey)
.fontSize(20)
.margin({ top: 10 })
}
.layoutWeight(1)
.margin({ left: 5 })
//删除数据的按钮
if (this.deleteCallback !== null) {
Button() {
Image($r('app.media.delete_red'))
.height(35).width(35)
.objectFit(ImageFit.Contain)
}
.type(ButtonType.Circle)
.height(50).width(50)
.backgroundColor('#F5F5F5')
.onClick(() => {
this.deleteCallback(this.book)
})
}
}
.width('100%')
.padding({ left: 15, right: 15 })
}
}
效果图:

视图组件,实现了一个搜索栏的效果,使用了Stack 布局,让放大镜能叠加在文本输入框上。
用Text 模拟TextInput 效果,点击进行跳转到搜索界面。
//引用路由,用于跳转界面
import router from '@ohos.router'
@Preview
@Component
export struct SearchBar {
build() {
Stack({ alignContent: Alignment.End }) {
//模拟TextInput的文本
Text($r('app.string.search_tip'))
.height('80%').width('94%')
.fontSize(16)
.padding({ left: 15 })
.margin('3%')
.backgroundColor('#A5A5A5')
.border({ radius: 20 })
//放大镜icon
Image($r('app.media.search_gray'))
.height(40).width(40)
.margin({ right: '5%' })
.objectFit(ImageFit.Contain)
}
.height(50).width('100%')
.backgroundColor('#F5F5F5')
.onClick(() => {
router.push({ url: 'pages/Query' })
})
}
}
效果图:

视图组件,实现了一个顶部标题栏的效果,提供了一个批量插入数据的操作按钮。
组件内定义回调函数的声明,在具体使用组件的界面在对回调函数进行实现,可以学习这种设计组件的方法。
@Component
export struct TitleBar {
//定义 批量插入的回调函数
private batchInsertCallback = null
build() {
Row() {
//标题名称
Text($r('app.string.title'))
.fontColor(Color.White)
.fontSize(20)
.layoutWeight(1)
//批量插入 操作按钮
Button() {
Text($r('app.string.batch_insert'))
.fontColor(Color.White)
.fontSize(22)
.textAlign(TextAlign.End)
}
.type(ButtonType.Normal)
.height('100%')
.backgroundColor('#0D9FFB')
.onClick(() => {
this.batchInsertCallback()
})
}
.height('8%').width('100%')
.backgroundColor('#0D9FFB')
.padding({ left: 15, right: 15 })
}
}
index.ets是和用户完成交互的主要页面。
需要引入数据访问能力类、路由,前面定义的常量类、视图组件、数据模块类等。
//引入数据访问能力类
import dataAbility from '@ohos.data.dataAbility'
//引入路由,实现跳转界面
import router from '@ohos.router'
//引入定义的常量、视图组件
import { BASE_URI, COLUMNS, DA_HELPER } from '../model/DaHelperConst'
import { BookView } from '../component/BookView'
import { TitleBar } from '../component/TitleBar'
import { SearchBar } from '../component/SearchBar'
//引入数据模块类
import { BookModel, initValuesBuckets, getListFromResultSet } from '../model/BookDataModel'
通过DA_HELPER查询数据实现页面显示图书列表效果,实现删除和批量插入数据的效果。
@Entry
@Component
struct Index {
@State bookList: Array<BookModel> = []
//生命周期回调,自动执行,页面显示前
//页面显示时触发一次,包括路由过程、应用进入前后台等场景,仅@Entry修饰的自定义组件生效。
onPageShow() {
this.queryAll()
}
queryAll = () => {
console.info(TAG + ' queryAll')
//获取谓词
let predicates = new dataAbility.DataAbilityPredicates()
//使用DA_HELPER 查询数据
DA_HELPER.query(BASE_URI, COLUMNS, predicates, (err, resultSet) => {
//重新封装查询结果
this.bookList = getListFromResultSet(resultSet)
})
}
deleteCallback = (book) => {
let predicates = new dataAbility.DataAbilityPredicates()
predicates.equalTo('id', book.id)
//使用DA_HELPER 删除数据
DA_HELPER.delete(BASE_URI, predicates, (err, num) => {
console.info(TAG + ' delete num=' + num)
this.queryAll()
})
}
batchInsertCallback = () => {
let valuesBuckets = initValuesBuckets()
//使用DA_HELPER 批量插入数据
DA_HELPER.batchInsert(BASE_URI, valuesBuckets, (err, num) => {
console.info(TAG + ' batch insert num=' + num)
this.queryAll()
})
}
build代码块,实现了列表显示的效果,使用了Stack布局,List等组件。
点击行,跳转到更新数据界面,传递book对象过去,注意跳转的路由要在config.json配置好。
build() {
Column() {
//标题栏
TitleBar({ batchInsertCallback: this.batchInsertCallback })
//搜索栏
SearchBar()
//列表
Stack({ alignContent: Alignment.BottomEnd }) {
//列表显示
List() {
ForEach(this.bookList, item => {
ListItem() {
BookView({ book: item, deleteCallback: this.deleteCallback })
}
.onClick(() => {
//点击行,跳转到更新数据界面,传递book对象过去
router.push({ url: 'pages/Update', params: { book: item } })
})
}, item => JSON.stringify(item))
}
.width('100%')
.margin({ bottom: 100 })
.constraintSize({ minHeight: '100%' })
.divider({ strokeWidth: 1, color: Color.Gray, startMargin: 10, endMargin: 10 })
//添加单条数据按钮
Button() {
Image($r('app.media.add'))
}
.type(ButtonType.Circle)
.width(60)
.height(60)
.backgroundColor('#0D9FFB')
.margin({ bottom: 150, right: 50 })
.onClick(() => {
console.info(TAG + ' insert onClick')
let valuesBuckets = { name: 'Book name', introduction: 'Book introduction' }
DA_HELPER.insert(BASE_URI, valuesBuckets, (err, num) => {
console.info(TAG + ' insert num=' + num)
this.bookList.push({ id: num, name: 'Book name', introduction: 'Book introduction' })
})
})
}
.width('100%').height('100%')
}
.width('100%').height('100%')
}
效果图:

引入依赖和index.ets类似:
import router from '@ohos.router';
import dataAbility from '@ohos.data.dataAbility'
import { BASE_URI, COLUMNS, DA_HELPER } from '../model/DaHelperConst'
import { BookModel, getListFromResultSet } from '../model/BookDataModel'
import { BookView } from '../component/BookView'
查询数据:
//查询数据
query(queryStr) {
let predicates = new dataAbility.DataAbilityPredicates()
//根据名字或介绍模糊匹配
predicates.contains('name', queryStr)
.or()
.contains('introduction', queryStr)
DA_HELPER.query(BASE_URI, COLUMNS, predicates, (err, resultSet) => {
this.bookList = getListFromResultSet(resultSet)
})
}
列表显示,和index.ets 类似,没有了删除按钮。
使用了ForEach、Stack、 TextInput 等组件, TextInput组件的onChange事件触发查询。
build() {
Column() {
Row() {
Image($r('app.media.ic_back'))
.width(40).height(40)
.objectFit(ImageFit.Contain)
.onClick(() => {
router.back()
})
Text($r('app.string.title'))
.fontColor(Color.White)
.fontSize(20)
.layoutWeight(1)
}
.height(50).width('100%')
.backgroundColor('#0D9FFB')
.padding({ left: 10, right: 10 })
Stack({ alignContent: Alignment.End }) {
TextInput({ placeholder: $r('app.string.search_placeholder')})
.height('85%').width('94%')
.padding({ left: 15 })
.margin('3%')
.backgroundColor('#F0F0F0')
.border({ radius: 20 })
//触发查询
.onChange((value: string) => {
console.info(TAG + ' query str=' + value)
if (value !== '') {
this.query(value)
}else{
this.bookList = []
}
})
Image($r('app.media.search_gray'))
.height(40).width(40)
.margin({ right: '5%' })
.objectFit(ImageFit.Contain)
}
.width('100%').height(50)
.backgroundColor('#F5F5F5')
List() {
ForEach(this.bookList, item => {
ListItem() {
BookView({ book: item, deleteCallback: null })
}
.onClick(() => {
router.push({ url: 'pages/update', params: { book: item } })
})
}, item => JSON.stringify(item))
}
.width('100%')
.layoutWeight(1)
.divider({ strokeWidth: 1, color: Color.Gray, startMargin: 10, endMargin: 10 })
}
}
复制 
引入依赖:
//引入依赖
import router from '@ohos.router';
import prompt from '@system.prompt';
import dataAbility from '@ohos.data.dataAbility'
import { BASE_URI, DA_HELPER } from '../model/DaHelperConst'
import { BookModel } from '../model/BookDataModel'
声明BookModel的变量,从router中接收携带的参数book对象,用于原信息的显示。
@Entry
@Component
struct Update {
//从router中接收携带的参数book对象,用于原信息的显示
private book: BookModel = <BookModel> router.getParams()["book"]
使用DA_HELPER 更新数据,更新完返回列表界面。
updateBook = () => {
let predicates = new dataAbility.DataAbilityPredicates()
predicates.equalTo('id', this.book.id)
let valuesBucket = {
'name': this.book.name,
'introduction': this.book.introduction
}
DA_HELPER.update(BASE_URI, valuesBucket, predicates, (err, num) => {
console.info(TAG + ' update book num=' + num)
router.back()
})
}
显示要修改的图书信息,支持修改,支持返回、提交修改按钮。
使用了Scroll、Image、Text、TextInput等组件。
build() {
Column() {
Row() {
//返回按钮
Image($r('app.media.ic_back'))
.width(40).height(40)
.objectFit(ImageFit.Contain)
.onClick(() => {
router.back()
})
//标题
Text($r('app.string.title'))
.fontColor(Color.White)
.fontSize(20)
.layoutWeight(1)
//提交修改按钮
Image($r('app.media.submit'))
.width(50).height(50)
.objectFit(ImageFit.Contain)
.onClick(() => {
console.info(TAG + ' update onClick,title=' + this.book.name)
if (this.book.name === '' || this.book.introduction === '') {
prompt.showToast({ message: 'Please input name or introduction' })
return
}
this.updateBook()
})
}
.height(50).width('100%')
.backgroundColor('#0D9FFB')
.padding({ left: 10, right: 10 })
//显示要修改的信息,支持滚动条
Scroll() {
Column() {
Image($r('app.media.book'))
.width(120).height(150)
.objectFit(ImageFit.Fill)
.margin(5)
Text($r('app.string.book_name'))
.fontWeight(FontWeight.Bold)
.fontSize(22)
.width('100%')
.margin({ top: 20 })
.fontColor(Color.Black)
TextInput({ placeholder: 'input name', text: this.book.name })
.type(InputType.Normal)
.placeholderColor(Color.Gray)
.fontSize(19)
.margin({ top: 10 })
//修改信息后更新book对象
.onChange((value: string) => {
this.book.name = value
})
Text($r('app.string.book_intro'))
.fontWeight(FontWeight.Bold)
.fontSize(22)
.width('100%')
.fontColor(Color.Black)
.margin({ top: 20 })
TextInput({ placeholder: 'input introduction', text: this.book.introduction })
.type(InputType.Normal)
.placeholderColor(Color.Gray)
.fontSize(19)
.margin({ right: 10, top: 10 })
//修改信息后更新book对象
.onChange((value: string) => {
this.book.introduction = value
})
}
.width('100%')
.constraintSize({ minHeight: '100%' })
.padding(15)
}.height('100%')
}
}
1、我们发现并没有调用 DataAbility 的代码,那DataAbility 怎么被跑起来的呢?
其实是 DataAbility 是会被自动运行的,只要在config.json 中做了配置,当应用启动后,DataAbility就会被自动运行,在DataAbility完成初始化后,会调用声明周期回调函数 onInitialized,完成数据库的初始化。
看一下 DataAbility 在config.json 中的配置:
"abilities": [
{
"visible": true,
"srcPath": "DataAbility",
"name": ".DataAbility",
"icon": "$media:icon",
"srcLanguage": "ets",
"description": "$string:description_dataability",
"type": "data",
"uri": "dataability://ohos.samples.etsdataability.DataAbility"
}
启动应用,从日志输出中我们可以看到 DataAbility 被运行。
05-17 23:00:11.016 526-1367/foundation I 01110/AppMgrService: [module_running_record.cpp(LaunchAbility:178)]ScheduleLaunchAbility ability:ohos.samples.etsdataability.DataAbility
那DataAbility 数据的增删改查,也没有看到调用的代码呢?
代码里只是用了DA_HELPER对象来操作数据,并没有调用DataAbility/data.ts 的 insert/batchInsert/query/update/delete 这些函数,
其实是 DA_HELPER 在初始化时 绑定的 BASE_URI(如下) 和 config.json文件中 DataAbility 的uri 是一致的,可以看上面config.json 的配置中uri的值。
(注意 config.json中的 uri 只能是 “dataablity://xxxxxxxxx” ,两道杠 )。
//定义 数据访问URI 常量
export const BASE_URI = 'dataability:///ohos.samples.etsdataability.DataAbility'
//获取一个DataAbility的帮助类
export const DA_HELPER = featureAbility.acquireDataAbilityHelper(BASE_URI)
有关BASE_URI格式说明参见下图,更详尽的参考。

2、DataAbility/data.ts 中创表语句中的表名,注意要和TABLE_NAME常量保持一致,否则数据无法插入成功。
我们可以在这个基础上去扩展库、扩展表,去实现我们自己应用的数据管理。