HarmonyOS學習路之開發篇——Data Ability
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:查詢引數。 f
- ragment:可以用於指示要訪問的子資源。
URI示例:
- 跨裝置場景:dataability://device_id/com.domainname.dataability.persondata/person/10
- 本地裝置:dataability:///com.domainname.dataability.persondata/person/10
建立Data
使用Data模板的Ability形式仍然是Ability,因此,開發者需要為應用新增一個或多個Ability的子類,來提供程式與其他應用之間的介面。Data為結構化資料和檔案提供了不同API介面供使用者使用,因此,開發者需要首先確定好使用何種型別的資料。本章節主要講述了建立Data的基本步驟和需要使用的介面。Data提供方可以自定義資料的增、刪、改、查,以及檔案開啟等功能,並對外提供這些介面。
確定資料儲存方式
確定資料的儲存方式,Data支援以下兩種資料形式:
- 檔案資料:如文字、圖片、音樂等。
- 結構化資料:如資料庫等。
實現UserDataAbility
UserDataAbility用於接收其他應用傳送的請求,提供外部程式訪問的入口,從而實現應用間的資料訪問。
實現UserDataAbility,需要在“Project”視窗當前工程的主目錄(“entry > src > main > java > com.xxx.xxx”)選擇“File > New > Ability > Empty Data Ability”,設定“Data Name”後完成UserDataAbility的建立。
Data提供了檔案儲存和資料庫儲存兩組介面供使用者使用。
檔案儲存
開發者需要在Data中重寫FileDescriptor openFile(Uri uri, String mode)方法來操作檔案:uri為客戶端傳入的請求目標路徑;mode為開發者對檔案的操作選項,可選方式包含“r”(讀), “w”(寫), “rw”(讀寫)等。
ohos.rpc.MessageParcel類提供了一個靜態方法,用於獲取MessageParcel例項。開發者可通過獲取到的MessageParcel例項,使用dupFileDescriptor()函式複製待操作檔案流的檔案描述符,並將其返回,供遠端應用訪問檔案。
示例:根據傳入的uri開啟對應的檔案
private static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0xD00201, "Data_Log");
@Override
public FileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
// 建立messageParcel
MessageParcel messageParcel = MessageParcel.obtain();
File file = new File(uri.getDecodedPathList().get(0)); //get(0)是獲取URI完整欄位中查詢引數欄位。
if (mode == null || !"rw".equals(mode)) {
file.setReadOnly();
}
FileInputStream fileIs = new FileInputStream(file);
FileDescriptor fd = null;
try {
fd = fileIs.getFD();
} catch (IOException e) {
HiLog.info(LABEL_LOG, "failed to getFD");
}
// 繫結檔案描述符
return messageParcel.dupFileDescriptor(fd);
}
資料庫儲存1、初始化資料庫連線。 系統會在應用啟動時呼叫onStart()方法建立Data例項。在此方法中,開發者應該建立資料庫連線,並獲取連線物件,以便後續和資料庫進行操作。為了避免影響應用啟動速度,開發者應當儘可能將非必要的耗時任務推遲到使用時執行,而不是在此方法中執行所有初始化。
示例:初始化的時候連線資料庫
private static final String DATABASE_NAME = "UserDataAbility.db";
private static final String DATABASE_NAME_ALIAS = "UserDataAbility";
private static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0xD00201, "Data_Log");
private OrmContext ormContext = null;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
DatabaseHelper manager = new DatabaseHelper(this);
ormContext = manager.getOrmContext(DATABASE_NAME_ALIAS, DATABASE_NAME, BookStore.class);
}
2、編寫資料庫操作方法。 Ability定義了6個方法供使用者處理對資料庫表資料的增刪改查。這6個方法在Ability中已預設實現,開發者可按需重寫。 |方法|描述| |:--|--| | ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) | 查詢資料庫 | |int insert(Uri uri, ValuesBucket value) | 向資料庫中插入單條資料 | |int batchInsert(Uri uri, ValuesBucket[] values) | 向資料庫中插入多條資料 | |int delete(Uri uri, DataAbilityPredicates predicates) | 刪除一條或多條資料 | |int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates)| 更新資料庫 | |DataAbilityResult[] executeBatch(ArrayList<DataAbilityOperation> operations)| 批量操作資料庫 |
3、批量操作資料庫 這些方法的使用說明如下:
- query() 該方法接收三個引數,分別是查詢的目標路徑,查詢的列名,以及查詢條件,查詢條件由類DataAbilityPredicates構建。根據傳入的列名和查詢條件查詢使用者表的程式碼示例如下:
public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) {
if (ormContext == null) {
HiLog.error(LABEL_LOG, "failed to query, ormContext is null");
return null;
}
// 查詢資料庫
OrmPredicates ormPredicates = DataAbilityUtils.createOrmPredicates(predicates,User.class);
ResultSet resultSet = ormContext.query(ormPredicates, columns);
if (resultSet == null) {
HiLog.info(LABEL_LOG, "resultSet is null");
}
// 返回結果
return resultSet;
}
- insert() 該方法接收兩個引數,分別是插入的目標路徑和插入的資料值。其中,插入的資料由ValuesBucket封裝,服務端可以從該引數中解析出對應的屬性,然後插入到資料庫中。此方法返回一個int型別的值用於標識結果。接收到傳過來的使用者資訊並把它儲存到資料庫中的程式碼示例如下:
public int insert(Uri uri, ValuesBucket value) {
// 引數校驗
if (ormContext == null) {
HiLog.error(LABEL_LOG, "failed to insert, ormContext is null");
return -1;
}
// 構造插入資料
User user = new User();
user.setUserId(value.getInteger("userId"));
user.setFirstName(value.getString("firstName"));
user.setLastName(value.getString("lastName"));
user.setAge(value.getInteger("age"));
user.setBalance(value.getDouble("balance"));
// 插入資料庫
boolean isSuccessful = ormContext.insert(user);
if (!isSuccessful) {
HiLog.error(LABEL_LOG, "failed to insert");
return -1;
}
isSuccessful = ormContext.flush();
if (!isSuccessful) {
HiLog.error(LABEL_LOG, "failed to insert flush");
return -1;
}
DataAbilityHelper.creator(this, uri).notifyChange(uri);
int id = Math.toIntExact(user.getRowId());
return id;
}
- batchInsert() 該方法為批量插入方法,接收一個ValuesBucket陣列用於單次插入一組物件。它的作用是提高插入多條重複資料的效率。該方法系統已實現,開發者可以直接呼叫。
- delete() 該方法用來執行刪除操作。刪除條件由類DataAbilityPredicates構建,服務端在接收到該引數之後可以從中解析出要刪除的資料,然後到資料庫中執行。根據傳入的條件刪除使用者表資料的程式碼示例如下:
public int delete(Uri uri, DataAbilityPredicates predicates) {
if (ormContext == null) {
HiLog.error(LABEL_LOG, "failed to delete, ormContext is null");
return -1;
}
OrmPredicates ormPredicates = DataAbilityUtils.createOrmPredicates(predicates,User.class);
int value = ormContext.delete(ormPredicates);
DataAbilityHelper.creator(this, uri).notifyChange(uri);
return value;
}
- update() 此方法用來執行更新操作。使用者可以在ValuesBucket引數中指定要更新的資料,在DataAbilityPredicates中構建更新的條件等。更新使用者表的資料的程式碼示例如下:
public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) {
if (ormContext == null) {
HiLog.error(LABEL_LOG, "failed to update, ormContext is null");
return -1;
}
OrmPredicates ormPredicates = DataAbilityUtils.createOrmPredicates(predicates,User.class);
int index = ormContext.update(ormPredicates, value);
HiLog.info(LABEL_LOG, "UserDataAbility update value:" + index);
DataAbilityHelper.creator(this, uri).notifyChange(uri);
return index;
}
- executeBatch() 此方法用來批量執行操作。DataAbilityOperation中提供了設定操作型別、資料和操作條件的方法,使用者可自行設定自己要執行的資料庫操作。該方法系統已實現,開發者可以直接呼叫。
說明 上述程式碼示例中,初始化了資料庫類BookStore.class,並通過實體類User.class對該資料庫的表User進行增刪改查操作。 關於物件關係對映資料庫的具體邏輯,以及示例中BookStore.class與User.class的邏輯關係,可參考“物件關係對映資料庫開發指導”。
註冊UserDataAbility
和Service類似,開發者必須在配置檔案中註冊Data。 配置檔案中該欄位在建立Data Ability時會自動建立,name與建立的Data Ability一致。 需要關注以下屬性:
- type: 型別設定為data
- uri: 對外提供的訪問路徑,全域性唯一
- permissions: 訪問該data ability時需要申請的訪問許可權 說明 如果許可權非系統許可權,需要在配置檔案中進行自定義。請參考許可權開發指導中關於“自定義許可權”的相關說明。
{
"name": ".UserDataAbility",
"type": "data",
"visible": true,
"uri": "dataability://com.example.myapplication5.DataAbilityTest",
"permissions": [
"com.example.myapplication5.DataAbility.DATA"
]
}
訪問Data
開發者可以通過DataAbilityHelper類來訪問當前應用或其他應用提供的共享資料。DataAbilityHelper作為客戶端,與提供方的Data進行通訊。Data接收到請求後,執行相應的處理,並返回結果。DataAbilityHelper提供了一系列與Data Ability對應的方法。
下面介紹DataAbilityHelper具體的使用步驟。
宣告使用許可權
如果待訪問的Data聲明瞭訪問需要許可權,則訪問此Data需要在配置檔案中宣告需要此許可權。宣告請參考許可權申請欄位說明。
"reqPermissions": [
{
"name": "com.example.myapplication5.DataAbility.DATA"
},
// 訪問檔案還需要新增訪問儲存讀寫許可權
{
"name": "ohos.permission.READ_USER_STORAGE"
},
{
"name": "ohos.permission.WRITE_USER_STORAGE"
}
]
建立DataAbilityHelper
DataAbilityHelper為開發者提供了creator()方法來建立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(檔案描述符),把檔案描述符封裝成流,開發者就可以對檔案流進行自定義處理。 訪問檔案示例:
// 讀取檔案描述符
FileDescriptor fd = helper.openFile(uri, "r");
FileInputStream fis = new FileInputStream(fd);
// 使用檔案描述符封裝成的檔案流,進行檔案操作
- 訪問資料庫 DataAbilityHelper為開發者提供了增、刪、改、查以及批量處理等方法來操作資料庫。 說明 對資料庫的操作方法,詳見資料管理中各資料庫型別的開發指南。
方法 | 描述 |
---|---|
ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) | 查詢資料庫 |
int insert(Uri uri, ValuesBucket value) | 向資料庫中插入單條資料 |
int batchInsert(Uri uri, ValuesBucket[] values) | 向資料庫中插入多條資料 |
int delete(Uri uri, DataAbilityPredicates predicates) | 刪除一條或多條資料 |
int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) | 更新資料庫 |
DataAbilityResult[] executeBatch(ArrayList<DataAbilityOperation> operations) | 批量操作資料庫 |
這些方法的使用說明如下:
- query() 查詢方法,其中uri為目標資源路徑,columns為想要查詢的欄位。開發者的查詢條件可以通過DataAbilityPredicates來構建。查詢使用者表中id在101-103之間的使用者,並把結果打印出來,程式碼示例如下:
DataAbilityHelper helper = DataAbilityHelper.creator(this);
// 構造查詢條件
DataAbilityPredicates predicates = new DataAbilityPredicates();
predicates.between("userId", 101, 103);
// 進行查詢
ResultSet resultSet = helper.query(uri, columns, predicates);
// 處理結果
resultSet.goToFirstRow();
do {
// 在此處理ResultSet中的記錄;
} while(resultSet.goToNextRow());
- insert() 新增方法,其中uri為目標資源路徑,ValuesBucket為要新增的物件。插入一條使用者資訊的程式碼示例如下:
DataAbilityHelper helper = DataAbilityHelper.creator(this);
// 構造插入資料
ValuesBucket valuesBucket = new ValuesBucket();
valuesBucket.putString("name", "Tom");
valuesBucket.putInteger("age", 12);
helper.insert(uri, valuesBucket);
- batchInsert() 批量插入方法,和insert()類似。批量插入使用者資訊的程式碼示例如下:
DataAbilityHelper helper = DataAbilityHelper.creator(this);
// 構造插入資料
ValuesBucket[] values = new ValuesBucket[2];
values[0] = new ValuesBucket();
values[0].putString("name", "Tom");
values[0].putInteger("age", 12);
values[1] = new ValuesBucket();
values[1].putString("name", "Tom1");
values[1].putInteger("age", 16);
helper.batchInsert(uri, values);
- delete() 刪除方法,其中刪除條件可以通過DataAbilityPredicates來構建。刪除使用者表中id在101-103之間的使用者,程式碼示例如下:
DataAbilityHelper helper = DataAbilityHelper.creator(this);
// 構造刪除條件
DataAbilityPredicates predicates = new DataAbilityPredicates();
predicates.between("userId", 101, 103);
helper.delete(uri, predicates);
- update() 更新方法,更新資料由ValuesBucket傳入,更新條件由DataAbilityPredicates來構建。更新id為102的使用者,程式碼示例如下:
DataAbilityHelper helper = DataAbilityHelper.creator(this);
// 構造更新條件
DataAbilityPredicates predicates = new DataAbilityPredicates();
predicates.equalTo("userId", 102);
// 構造更新資料
ValuesBucket valuesBucket = new ValuesBucket();
valuesBucket.putString("name", "Tom");
valuesBucket.putInteger("age", 12);
helper.update(uri, valuesBucket, predicates);
- executeBatch() 此方法用來執行批量操作。DataAbilityOperation中提供了設定操作型別、資料和操作條件的方法,開發者可自行設定自己要執行的資料庫操作。插入多條資料的程式碼示例如下:
DataAbilityHelper helper = DataAbilityHelper.creator(abilityObj, insertUri);
// 構造批量操作
ValuesBucket value1 = initSingleValue();
DataAbilityOperation opt1 = DataAbilityOperation.newInsertBuilder(insertUri).withValuesBucket(value1).build();
ValuesBucket value2 = initSingleValue2();
DataAbilityOperation opt2 = DataAbilityOperation.newInsertBuilder(insertUri).withValuesBucket(value2).build();
ArrayList<DataAbilityOperation> operations = new ArrayList<DataAbilityOperation>();
operations.add(opt1);
operations.add(opt2);
DataAbilityResult[] result = helper.executeBatch(insertUri, operations);
相關例項
針對Data Ability開發,有以下示例工程可供參考:
-
DataAbility 本示例演示瞭如何使用Data Ability對資料庫進行增、刪、改、查,以及讀取文字檔案。 針對Data Ability開發,有以下Codelabs可供參考:
-
關係型資料庫 基於Data Ability的關係型資料庫和資料管理能力,實現資料庫相關應用服務的快速開發。