前言(Data Ability)
使用Data模板的Ability又简称Data,有助于应用管理其自身和其他应用存储数据的访问,并提供与其他应用共享数据的方法。Data既可用于同设备不同应用的数据共享,也支持跨设备不同应用的数据共享。
数据的存放形式多样,可以是数据库,也可以是磁盘上的文件。Data对外提供对数据的增、删、改、查,以及打开文件等接口,这些接口的具体实现由开发者提供。
URI
Data的提供方和使用方都通过URI(Uniform Resource Identifier,统一资源标识符)来标识一个具体的数据,例如数据库中的某个表或磁盘上的某个文件。HarmonyOS的URI仍基于URI通用标准,格式如下:
其中:
- scheme:协议方案名,固定为“dataability”,代表Data Ability所使用的协议类型。
- authority:设备ID。如果为跨设备场景,则为目标设备的ID;如果为本地设备场景,则不需要填写。
- path:资源的路径信息,代表特定资源的位置信息。
- query:查询参数。
- fragment:可以用于指示要访问的子资源。
URI示例:
- 跨设备场景:dataability://device_id/com.domainname.dataability.persondata/person/10
- 本地设备:dataability:///com.domainname.dataability.persondata/person/10
说明
本地设备的“device_id”字段为空,因此在“dataability:”后面有三个“/”。
访问Data
开发者可以通过DataAbilityHelper类来访问当前应用或其他应用提供的共享数据。DataAbilityHelper作为客户端,与提供方的Data进行通信。Data接收到请求后,执行相应的处理,并返回结果。DataAbilityHelper提供了一系列与Data Ability对应的方法。
下面介绍DataAbilityHelper具体的使用步骤。
声明使用权限
如果待访问的Data声明了访问需要权限,则访问此Data需要在配置文件中声明需要此权限。
"reqPermissions": [
{
"name": "com.example.dataabilityhelperdemo.DataAbility.DATA"
}
]
如果访问的数据是文件,则还需要添加访问存储读、写的权限:ohos.permission.READ_USER_STORAGE和ohos.permission.WRITE_USER_STORAGE。
创建DataAbilityHelper
DataAbilityHelper为开发者提供了creator()方法(已过期),现在使用create()方法来创建DataAbilityHelper实例。该方法为静态方法,有多个重载。最常见的方法是通过传入一个context对象来创建DataAbilityHelper对象。
获取helper对象示例:
DataAbilityHelper helper = DataAbilityHelper.creator(this);
访问Data Ability
DataAbilityHelper为开发者提供了一系列的接口来访问不同类型的数据(文件、数据库等)。
- 访问文件
DataAbilityHelper为开发者提供了FileDescriptor openFile(Uri uri, String mode)方法来操作文件。此方法需要传入两个参数,其中uri用来确定目标资源路径,mode用来指定打开文件的方式,可选方式包含“r”(读), “w”(写), “rw”(读写),“wt”(覆盖写),“wa”(追加写),“rwt”(覆盖写且可读)。
该方法返回一个目标文件的FD(文件描述符),把文件描述符封装成流,开发者就可以对文件流进行自定义处理。
- 访问数据库
DataAbilityHelper为开发者提供了增、删、改、查以及批量处理等方法来操作数据库。
创建DataAbility
创建一个名为UserDataAbility的Data
public class UserDataAbility extends Ability {
private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");
@Override
public void onStart(Intent intent) {
super.onStart(intent);
HiLog.info(LABEL_LOG, "UserDataAbility onStart");
}
@Override
public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) {
return null;
}
@Override
public int insert(Uri uri, ValuesBucket value) {
HiLog.info(LABEL_LOG, "UserDataAbility insert");
return 999;
}
@Override
public int delete(Uri uri, DataAbilityPredicates predicates) {
return 0;
}
@Override
public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) {
return 0;
}
@Override
public FileDescriptor openFile(Uri uri, String mode) {
return null;
}
@Override
public String[] getFileTypes(Uri uri, String mimeTypeFilter) {
return new String[0];
}
@Override
public PacMap call(String method, String arg, PacMap extras) {
return null;
}
@Override
public String getType(Uri uri) {
return null;
}
}
自动生成增删改查、打开文件、获取文件类型、一个回调、获取Uri类型和一个onStart方法。
在config.json配置文件中自动添加了如下配置:
...
"abilities": [
{
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
],
"orientation": "unspecified",
"name": "com.example.dataabilityhelperdemo.MainAbility",
"icon": "$media:icon",
"description": "$string:mainability_description",
"label": "$string:entry_MainAbility",
"type": "page",
"launchType": "standard"
},
{
"permissions": [
"com.example.dataabilityhelperdemo.DataAbilityShellProvider.PROVIDER"
],
"name": "com.example.dataabilityhelperdemo.UserDataAbility",
"icon": "$media:icon",
"description": "$string:userdataability_description",
"type": "data",
"uri": "dataability://com.example.dataabilityhelperdemo.UserDataAbility"
}
]
如上配置中:
- type: 类型为data。
- uri:对外提供的访问路径,唯一。
- permissions:访问Data Ability时需要申请的访问权限。
关键代码:
//初始化文件
private void initFile() {
//获取文件目录
File dataDir = new File(this.getDataDir().toString());
if(!dataDir.exists()){
dataDir.mkdirs();
}
//目标文件
targetFile = new File(Paths.get(dataDir.toString(),"name.txt").toString());
RawFileEntry rawFileEntry = this.getResourceManager().getRawFileEntry("resources/rawfile/name.txt");
try {
Resource resource = rawFileEntry.openRawFile();
FileOutputStream fos = new FileOutputStream(targetFile);
byte[] buffer = new byte[4096];
int count =0;
while((count = resource.read(buffer)) >=0){
fos.write(buffer,0,count);
}
resource.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
initFile方法用于初始化文件,将源文件写入目标文件,ResourceManager类的getRawFileEntry方法,获取到RawFileEntry类,RawFileEntry类就代表rawfile目录下的文件,最后通过rawFileEntry.openRawFile()就可以获取到指定文件名的文件。在resource目录的rawfile目录下创建名为name.txt文件,内容如下:
HarmonyOS
效果展示
获取文件数据
ability_main.xml布局文件,点击按钮,显示文件里面的内容。
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<Button
ohos:id="$+id:button"
ohos:height="match_content"
ohos:width="match_parent"
ohos:text="获取数据"
ohos:text_size="40vp"/>
<Text
ohos:id="$+id:text_helloworld"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text_size="40vp"
/>
</DirectionalLayout>
关键代码如下:
public class MainAbilitySlice extends AbilitySlice {
private Button button;
private Text textDesc;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
button = (Button)findComponentById(ResourceTable.Id_button);
textDesc = (Text)findComponentById(ResourceTable.Id_text_helloworld);
button.setClickedListener(listener ->this.getFile());
}
private void getFile() {
DataAbilityHelper helper = DataAbilityHelper.creator(this);
Uri uri = Uri.parse("dataability:///com.example.dataabilityhelperdemo.UserDataAbility");
try{
FileDescriptor fileDescriptor = null;
fileDescriptor = helper.openFile(uri,"r");
textDesc.setText(FileUtils.getFileContent(fileDescriptor));
}catch (DataAbilityRemoteException | IOException e){
e.printStackTrace();
}
}
}
FileUtils.java:
public class FileUtils {
public static String getFileContent(FileDescriptor fd)throws IOException{
FileInputStream fis = new FileInputStream(fd);
int a=0;
StringBuilder builder = new StringBuilder();
while ((a= fis.read()) !=-1){
builder.append((char) a);
}
fis.close();
return builder.toString();
}
}
源码下载地址
总结
访问文件的关键在于目标文件的文件描述符的获取,使用文件描述符封装成的文件流,进行文件操作。