文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

HarmonyOS Sample之DataAbility RDB数据库操作

2024-12-03 01:07

关注

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

DataAbility RDB数据库操作

介绍

使用Data模板的Ability(以下简称“Data”)有助于应用管理其自身和其他应用存储数据的访问,并提供与其他应用共享数据的方法。Data既可用于同设备不同应用的数据共享,也支持跨设备不同应用的数据共享。

数据的存放形式多样,可以是数据库,也可以是磁盘上的文件。Data对外提供对数据的增、删、改、查,以及打开文件等接口,这些接口的具体实现由开发者提供。

本示例演示了如何使用Data Ability对RDB数据库进行增、删、改、查,以及读取文本文件。

模仿手机的备忘录,实现了简单的操作。

搭建环境

安装DevEco Studio,详情请参考DevEco Studio下载

设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:

如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作

如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境

步骤

1.创建一个DataAbility和数据库常量类

a.创建一个Empty DataAbility

entity右键,New- Ability-Empty Data Ability,然后输入名称 NoteDataAbility


b.创建一个数据库常量类 Const.java

存放数据库名称、表名称、字段列名称、存储路径等

需要注意的是,

BASE_URI 3个杠后面的部分要和config.json Data Ability 声明的uri完全一致,否则应用无法启动

  1.  
  2. public class Const { 
  3.      
  4.     public static final String BASE_URI = "dataability:///ohos.samples.dataability.NoteDataAbility"
  5.  
  6.      
  7.     public static final String DB_NAME = "note.db"
  8.  
  9.      
  10.     public static final String DB_TAB_NAME = "note"
  11.  
  12.      
  13.     public static final String DB_COLUMN_ID = "Id"
  14.      
  15.     public static final String DB_COLUMN_TITLE = "noteTitle"
  16.  
  17.      
  18.     public static final String DB_COLUMN_TIME = "writeTime"
  19.  
  20.      
  21.     public static final String DB_COLUMN_CATEGORY = "noteCategory"
  22.      
  23.     public static final String DB_COLUMN_CONTENT = "noteContent"
  24.  
  25.      
  26.     public static final String DATA_PATH = "/note"
  27.  
  28.  
  29.      
  30.     public static final String FILE_NAME = "userdataability.txt"
  31.  

c.config.json相关配置

config.json涉及NoteDataAbility.java 的地方有3处,

第1处在module对象下,


第2处是abilities对象下,

permissions表示其他应用的能力调用当前能力所需的权限。

默认情况下隐藏"visible"字段(值为false),表示仅本应用可访问该Data,开发人员可根据需求修改permissions、visible值、uri等内容。当外部应用需要访问/控制此数据库字段时,在该Data Ability配置中增加"visible": true,并在外面应用的配置文件config.json中申请permissions权限。


第3处是reqPermissions对象下,

说明:如果待访问的Data Ability是由本应用创建,则可以不声明该权限。


2.声明数据库存储对象和数据库配置

在NoteDataAbility.java 添加如下代码

  1. //声明数据库存储对象 
  2. private RdbStore rdbStore; 
  3. //数据库配置,指定数据库名称 
  4. private StoreConfig storeConfig = StoreConfig.newDefaultConfig(Const.DB_NAME); 

3.实现打开RDB数据库回调函数

在NoteDataAbility.java 添加如下代码

  1. // 管理数据库创建、升级和降级。 
  2. // 您可以创建一个子类来实现 #onCreate、#onUpgrade 或 #onOpen 方法。  
  3. // 如果一个数据库已经存在,它将被打开; 如果不存在数据库,则将创建一个数据库。  
  4. // 在数据库升级过程中,也会调用该类的方法。 
  5. private RdbOpenCallback rdbOpenCallback = new RdbOpenCallback() { 
  6.     @Override 
  7.     public void onCreate(RdbStore rdbStore) { 
  8.         //创建表 
  9.         rdbStore.executeSql( 
  10.                 "create table if not exists " + Const.DB_TAB_NAME + "2 (" + 
  11.                         Const.DB_COLUMN_ID + " integer primary key autoincrement ," + 
  12.                         Const.DB_COLUMN_TITLE + " text not null," + 
  13.                         Const.DB_COLUMN_CONTENT + " text not null," + 
  14.                         Const.DB_COLUMN_TIME + " text not null," + 
  15.                         Const.DB_COLUMN_CATEGORY + " text not null" + 
  16.  
  17.                         ")" 
  18.         ); 
  19.     } 
  20.  
  21.     @Override 
  22.     public void onUpgrade(RdbStore rdbStore, int i, int i1) { 
  23.         //数据库升级 
  24.     } 
  25. }; 

4.初始化RDB数据库存储对象

在NoteDataAbility.java 添加如下代码

  1. @Override 
  2. public void onStart(Intent intent) { 
  3.     super.onStart(intent); 
  4.     HiLog.info(LABEL_LOG, "NoteDataAbility onStart"); 
  5.     //数据库帮助类 
  6.     DatabaseHelper databaseHelper = new DatabaseHelper(this); 
  7.     //初始化RDB数据库存储对象 
  8.     rdbStore = databaseHelper.getRdbStore(storeConfig, 1, rdbOpenCallback); 
  9.  

5.实现对数据库的基本操作函数

NoteDataAbility.java操作数据库的方法都需要自己实现,包括:添加、修改、查询、删除,还有打开文件,主要使用rdbStore对象。

  1. @Override 
  2. public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) { 
  3.     HiLog.info(LABEL_LOG, "NoteDataAbility query"); 
  4.     RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates, Const.DB_TAB_NAME); 
  5.     return rdbStore.query(rdbPredicates, columns); 
  6.  
  7. @Override 
  8. public int insert(Uri uri, ValuesBucket value) { 
  9.     HiLog.info(LABEL_LOG, "NoteDataAbility insert"); 
  10.     //long to int 
  11.     int rowId = (int) rdbStore.insert(Const.DB_TAB_NAME, value); 
  12.     //通知观察者数据发生变化 
  13.     DataAbilityHelper.creator(this).notifyChange(uri); 
  14.     return rowId; 
  15.  
  16. @Override 
  17. public int delete(Uri uri, DataAbilityPredicates predicates) { 
  18.     //rdb 条件,通过DataAbilityUtils将DataAbilityPredicates转成 RdbPredicates 
  19.     RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates, Const.DB_TAB_NAME); 
  20.     //执行删除 
  21.     int rowId = rdbStore.delete(rdbPredicates); 
  22.     HiLog.info(LABEL_LOG, "%{public}s""delete"); 
  23.     //通知观察者数据发生变化 
  24.     DataAbilityHelper.creator(this).notifyChange(uri); 
  25.     return rowId; 
  26.  
  27. @Override 
  28. public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) { 
  29.     //rdb 条件,通过DataAbilityUtils将DataAbilityPredicates转成 RdbPredicates 
  30.     RdbPredicates rdbPredicates = DataAbilityUtils.createRdbPredicates(predicates, Const.DB_TAB_NAME); 
  31.     int rowId =rdbStore.update(value, rdbPredicates); 
  32.     //通知观察者数据发生变化 
  33.     DataAbilityHelper.creator(this).notifyChange(uri); 
  34.     return rowId; 
  35.  
  36. @Override 
  37. public FileDescriptor openFile(Uri uri, String mode) { 
  38.  
  39.     //获取应用程序在设备内部存储器上存放文件的目录 
  40.     File file = new File(getFilesDir(), uri.getDecodedQuery()); 
  41.  
  42.     FileDescriptor fileDescriptor = null
  43.     try { 
  44.         FileInputStream fis = new FileInputStream(file); 
  45.         //获取FD 
  46.         fileDescriptor = fis.getFD(); 
  47.         //获取一个新的文件描述符,它是现有文件描述符的副本 
  48.         return MessageParcel.dupFileDescriptor(fileDescriptor); 
  49.     } catch (IOException e) { 
  50.         e.printStackTrace(); 
  51.     } 
  52.     return fileDescriptor; 

6.数据的订阅和通知

在NoteDataAbility.java 中, 我们看到insert/update/delete方法都有一行。

  1. DataAbilityHelper.creator(this).notifyChange(uri); 

目的是在数据库数据发生变化时,通知数据的订阅者。

而在MainAbilitySlice.java 类中有如下方法,在OnStart()中被调用,实现了数据变化的订阅。

  1. private void initDatabaseHelper() { 
  2.     //创建实例 
  3.     dataAbilityHelper = DataAbilityHelper.creator(this); 
  4.     //注册一个观察者来观察给定 Uri 指定的数据,dataObserver表示 IDataAbilityObserver 对象 
  5.     dataAbilityHelper.registerObserver(Uri.parse(Const.BASE_URI), dataAbilityObserver); 

同时,数据变化订阅方还需要实现IDataAbilityObserver接口,在数据变化时会自动回调,完成对应的逻辑处理。

  1. //观察者模式,数据变化时回调 
  2. private final IDataAbilityObserver dataAbilityObserver=() -> { 
  3.     HiLog.info(LABEL, "%{public}s""database changed"); 
  4.     //筛选数据 
  5.     initLists(this); 
  6. }; 

当数据订阅者不再需要订阅Data变化时,则调用unregisterObserver​(Uri uri, IDataAbilityObserver dataObserver)方法取消。

  1. @Override 
  2. protected void onStop() { 
  3.     super.onStop(); 
  4.     dataAbilityHelper.unregisterObserver(Uri.parse(Const.BASE_URI), dataAbilityObserver); 

观察者模式的作用在于当数据库表格的内容产生变化时,可以主动通知与该表格数据相关联的进程或者应用,从而使得相关进程或者应用接收到数据变化后完成相应的处理。

7.访问Data Ability,新建AddNoteAbility,在AddNoteAbilitySlice实现数据的添加和修改

开发者可以通过DataAbilityHelper类来访问当前应用或其他应用提供的共享数据。

DataAbilityHelper作为客户端,与提供方的Data进行通信。DataAbilityHelper提供了一系列与Data Ability通信的方法。

a.数据的添加

  1.  
  2. private void saveNote(Component component) { 
  3.     ValuesBucket valuesBucket = new ValuesBucket(); 
  4.     TextField noteTitle = (TextField) findComponentById(ResourceTable.Id_add_note_title); 
  5.     if (noteTitle.getText().isEmpty()) { 
  6.         DialLogUtils dialog = new DialLogUtils(this, "不能为空!"); 
  7.         dialog.showDialog(); 
  8.         return
  9.     } 
  10.     TextField noteContent = (TextField) findComponentById(ResourceTable.Id_add_note_content); 
  11.     if (noteContent.getText().isEmpty()) { 
  12.         DialLogUtils dialog = new DialLogUtils(this, "内容不能为空!"); 
  13.         dialog.showDialog(); 
  14.         return
  15.     } 
  16.     Text noteCategory = (Text) findComponentById(ResourceTable.Id_add_note_category); 
  17.     Text noteTime = (Text) findComponentById(ResourceTable.Id_add_note_time); 
  18.  
  19.     HiLog.debug(LABEL, "%{public}s""saveNote, noteId:[" + noteId + "],noteCategory:" + noteCategory.getText()); 
  20.     int rowId; 
  21.     //放入键值 
  22.     valuesBucket.putString(Const.DB_COLUMN_TITLE, noteTitle.getText()); 
  23.     valuesBucket.putString(Const.DB_COLUMN_CATEGORY, noteCategory.getText()); 
  24.     valuesBucket.putString(Const.DB_COLUMN_CONTENT, noteContent.getText()); 
  25.     valuesBucket.putString(Const.DB_COLUMN_TIME, noteTime.getText()); 
  26.     try { 
  27.         if (noteId.isEmpty()) { 
  28.             HiLog.debug(LABEL, "%{public}s""saveNote, insert"); 
  29.             //插入数据 
  30.             rowId = dataAbilityHelper.insert(Uri.parse(Const.BASE_URI + Const.DATA_PATH), valuesBucket); 
  31.             HiLog.debug(LABEL, "%{public}s""insert,rowId:" + rowId); 
  32.  
  33.         } else { 
  34.             HiLog.debug(LABEL, "%{public}s""saveNote, update"); 
  35.             //指定修改谓语 
  36.             DataAbilityPredicates predicates = new DataAbilityPredicates(); 
  37.             predicates.equalTo(Const.DB_COLUMN_ID, noteId); 
  38.             //修改数据 
  39.             rowId = dataAbilityHelper.update(Uri.parse(Const.BASE_URI + Const.DATA_PATH), valuesBucket, predicates); 
  40.             HiLog.debug(LABEL, "%{public}s""update,rowId:" + rowId); 
  41.         } 
  42.  
  43.         //返回列表页 
  44.         backListPage(); 
  45.     } catch (DataAbilityRemoteException | IllegalStateException exception) { 
  46.         HiLog.error(LABEL, "%{public}s""insert: dataRemote exception|illegalStateException"); 
  47.     } 

b.修改和删除数据

  1. @Override 
  2. public void onStart(Intent intent) { 
  3.     super.onStart(intent); 
  4.     //设置UI布局资源 
  5.     super.setUIContent(ResourceTable.Layout_ability_add_note); 
  6.     // 
  7.     initDatabaseHelper(); 
  8.     //返回按钮 
  9.     Component backButton = findComponentById(ResourceTable.Id_back_image); 
  10.     backButton.setClickedListener(component -> terminateAbility()); 
  11.     TextField noteContent = (TextField) findComponentById(ResourceTable.Id_add_note_content); 
  12.  
  13.  
  14.     //修改笔记 
  15.     if (intent.hasParameter("Id")) { 
  16.         HiLog.info(LABEL, "%{public}s""change data coming"); 
  17.         noteId = intent.getStringParam("Id"); 
  18.         HiLog.info(LABEL, "%{public}s""noteId:" + noteId); 
  19.         if (noteId != null) { 
  20.             DataAbilityPredicates predicates = new DataAbilityPredicates(); 
  21.             predicates.equalTo(Const.DB_COLUMN_ID, noteId); 
  22.             //查询数据 
  23.             NoteListItemInfo itemInfo = queryOne(predicates); 
  24.             HiLog.info(LABEL, "%{public}s""noteTitle:" + itemInfo.getNoteTitle() + ",category:" + itemInfo.getNoteCategory()); 
  25.             //设置显示 
  26.             TextField noteTitle = (TextField) findComponentById(ResourceTable.Id_add_note_title); 
  27.             noteTitle.setText(itemInfo.getNoteTitle()); 
  28.  
  29.             noteContent.setText(itemInfo.getNoteContent()); 
  30.  
  31.             Text category = (Text) findComponentById(ResourceTable.Id_add_note_category); 
  32.             category.setText(itemInfo.getNoteCategory()); 
  33.  
  34.             Text noteTime = (Text) findComponentById(ResourceTable.Id_add_note_time); 
  35.             noteTime.setText(itemInfo.getNoteTime()); 
  36.  
  37.  
  38.             Component deleteButton = findComponentById(ResourceTable.Id_delete_image); 
  39.             //设置删除按钮可用,只有修改笔记才能删除 
  40.             deleteButton.setClickable(true); 
  41.             //添加事件 
  42.             deleteButton.setClickedListener(component -> { 
  43.                 try { 
  44.                     int rowId = dataAbilityHelper.delete(Uri.parse(Const.BASE_URI + Const.DATA_PATH), predicates); 
  45.                     HiLog.info(LABEL, "%{public}s""deleteNote,rowId:" + rowId); 
  46.  
  47.                     //返回列表页 
  48.                     backListPage(); 
  49.                 } catch (DataAbilityRemoteException e) { 
  50.                     HiLog.error(LABEL, "%{public}s""delete: exception|DataAbilityRemoteException"); 
  51.                 } 
  52.             }); 
  53.         } 
  54.     } else { 
  55.         Text timeText = (Text) findComponentById(ResourceTable.Id_add_note_time); 
  56.         String time24 = sdf.format(new Date()); 
  57.         timeText.setText(time24); 
  58.     } 
  59.  
  60.     //保存笔记 
  61.     Component insertButton = findComponentById(ResourceTable.Id_finish_image); 
  62.     insertButton.setClickedListener(this::saveNote); 
  63.  

c.查询数据

  1. private NoteListItemInfo queryOne(DataAbilityPredicates predicates) { 
  2.     HiLog.info(LABEL, "%{public}s""database query"); 
  3.     String[] columns = new String[]{ 
  4.             Const.DB_COLUMN_ID, 
  5.             Const.DB_COLUMN_TITLE, Const.DB_COLUMN_TIME, 
  6.             Const.DB_COLUMN_CATEGORY, Const.DB_COLUMN_CONTENT}; 
  7.     try { 
  8.         ResultSet resultSet = dataAbilityHelper.query( 
  9.                 Uri.parse(Const.BASE_URI + Const.DATA_PATH), columns, predicates); 
  10.  
  11.         //无数据 
  12.         if (resultSet.getRowCount() == 0) { 
  13.             HiLog.info(LABEL, "%{public}s""query:No result found"); 
  14.             return null
  15.         } 
  16.         // 
  17.         resultSet.goToFirstRow(); 
  18.         //根据列索引获取列值 
  19.         String noteId = resultSet.getString(resultSet.getColumnIndexForName(Const.DB_COLUMN_ID)); 
  20.         String noteTitle = resultSet.getString(resultSet.getColumnIndexForName(Const.DB_COLUMN_TITLE)); 
  21.         String noteTime = resultSet.getString(resultSet.getColumnIndexForName(Const.DB_COLUMN_TIME)); 
  22.         String noteCategory = resultSet.getString(resultSet.getColumnIndexForName(Const.DB_COLUMN_CATEGORY)); 
  23.         String noteContent = resultSet.getString(resultSet.getColumnIndexForName(Const.DB_COLUMN_CONTENT)); 
  24.         Element image = ElementScatter.getInstance(getContext()).parse(ResourceTable.Graphic_icon_nodata); 
  25.         HiLog.info(LABEL, "%{public}s""set  show:" + noteCategory); 
  26.         // 
  27.         return new NoteListItemInfo(noteId, noteTitle, noteContent, noteTime, noteCategory, image); 
  28.  
  29.     } catch (DataAbilityRemoteException | IllegalStateException exception) { 
  30.         HiLog.error(LABEL, "%{public}s""query: dataRemote exception|illegalStateException"); 
  31.     } 
  32.     return null

实践中遇到的小知识点记录一下

1. 如何监听 TextField 文本变更事件

  1.  
  2. private void initSearchBtnEvent(AbilitySlice slice) { 
  3.     TextField searchTF = (TextField) findComponentById(ResourceTable.Id_tf_note_search); 
  4.     //添加文本观察器 TextObserver 以检测文本是否发生更改。 
  5.     searchTF.addTextObserver(new Text.TextObserver() { 
  6.         @Override 
  7.         public void onTextUpdated(String s, int i, int i1, int i2) { 
  8.             HiLog.info(LABEL, "addTextObserver 按键事件触发....."); 
  9.             //筛选数据 
  10.             initLists(slice); 
  11.         } 
  12.     }); 

2. ListContainer 组件添加点击事件

在 Provider 中 getComponent添加,在初始化Provider时传递AbilitySlice对象过来

  1. public ListItemProvider(List itemList, AbilityContext context,AbilitySlice slice) { 
  2.     this.itemList = itemList; 
  3.     this.context = context; 
  4.     this.typeFactory = new ListTypeFactory(); 
  5.     this.slice=slice; 
  6. @Override 
  7. public Component getComponent(int index, Component component, ComponentContainer componentContainer) { 
  8.     Component itemComponent = component; 
  9.     ViewHolder viewHolder; 
  10.     if (itemComponent == null) { 
  11.         itemComponent = LayoutScatter.getInstance(componentContainer.getContext()) 
  12.                 .parse(getItemComponentType(index), componentContainer, false); 
  13.  
  14.     } 
  15.     viewHolder = typeFactory.getViewHolder(getItemComponentType(index), itemComponent); 
  16.     viewHolder.setUpComponent(getItem(index), context); 
  17.  
  18.  
  19.     //设置点击事件 
  20.     itemComponent.setClickedListener(component1 -> { 
  21.         //获取noteId 
  22.         String noteId=""
  23.         if(getItem(index) instanceof NoteListItemInfo){ 
  24.             //HiLog.debug(LABEL, "%{public}s""ItemInfo instanceof SingleButtonDoubleLineListItemInfo"); 
  25.             noteId=((NoteListItemInfo)getItem(index)).getNoteId(); 
  26.         } 
  27.         HiLog.debug(LABEL, "%{public}s""noteId:" + noteId); 
  28.         //1.携带笔记ID参数,跳转到AddNoteAbilitySlice 
  29.         Intent intent = new Intent(); 
  30.         if(noteId!=null){ 
  31.             //保存要传递的参数 
  32.             intent.setParam("Id", noteId); 
  33.             Operation operation = new Intent.OperationBuilder() 
  34.                     .withDeviceId(""
  35.                     .withBundleName("com.buty.samples"
  36.                     .withAbilityName(AddNoteAbility.class).build(); 
  37.             intent.setOperation(operation); 
  38.  
  39.             slice.startAbility(intent); 
  40.         }else { 
  41.             HiLog.error(LABEL, "%{public}s""noteId is null"); 
  42.         } 
  43.     }); 
  44.  
  45.     return itemComponent; 

效果展示

文章相关附件可以点击下面的原文链接前往下载。

原文链接:https://harmonyos.51cto.com/posts/7386

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯