介紹
本篇Codelab基于元服務卡片的能力,實現帶有卡片的電影應用,介紹卡片的開發過程和生命周期實現。需要完成以下功能:
- 元服務卡片,用于在桌面上添加2x2或2x4規格元服務卡片。
- 關系型數據庫,用于創建、查詢、添加、刪除卡片數據。
相關概念
- [關系型數據庫]:關系型數據庫基于SQLite組件提供了一套完整的對本地數據庫進行管理的機制,對外提供了一系列的增、刪、改、查等接口,也可以直接運行用戶輸入的SQL語句來滿足復雜的場景需要。
- [元服務卡片]:卡片是一種界面展示形式,可以將應用的重要信息或操作前置到卡片,以達到服務直達、減少體驗層級的目的。
- 卡片提供方:顯示卡片內容,控制卡片布局以及控件點擊事件。
- 卡片使用方:顯示卡片內容的宿主應用,控制卡片在宿主中展示的位置。
- 卡片管理服務:用于管理系統中所添加卡片的常駐代理服務,包括卡片對象的管理與使用,以及卡片周期性刷新等。
環境搭建
軟件要求
- [DevEco Studio]版本:DevEco Studio 3.1 Release。
- OpenHarmony SDK版本:API version 9。
- 鴻蒙開發參考文檔:[
qr23.cn/AKFP8k
]
硬件要求
- 開發板類型:[潤和RK3568開發板]。
- OpenHarmony系統:3.2 Release。
環境搭建
- [獲取OpenHarmony系統版本]:標準系統解決方案(二進制)。以3.2 Release版本為例:
- 搭建燒錄環境。
- [完成DevEco Device Tool的安裝]
- [完成RK3568開發板的燒錄]
- 搭建開發環境。
- 開始前請參考[工具準備],完成DevEco Studio的安裝和開發環境配置。
- 開發環境配置完成后,請參考[使用工程向導]創建工程(模板選擇“Empty Ability”)。
- 工程創建完成后,選擇使用[真機進行調測]。
代碼結構解讀
本篇Codelab只對核心代碼進行講解,對于完整代碼,我們會在gitee中提供。
├──entry/src/main/ets // 代碼區
│ ├──common
│ │ ├──constants
│ │ │ ├──CommonConstants.ets // 常量類
│ │ │ └──StyleConstants.ets // 格式常量類
│ │ ├──datasource
│ │ │ ├──DataSource.ets // 懶加載數據源
│ │ │ └──MovieListData.ets // 電影列表數據
│ │ └──utils
│ │ ├──CommonUtils.ets // 數據操作工具類
│ │ ├──GlobalContext.ets // 全局上下文工具類
│ │ └──Logger.ets // 日志打印工具類
│ ├──detailsability
│ │ └──EntryDetailsAbility.ets // 電影詳情入口類
│ ├──entryability
│ │ └──EntryAbility.ets // 程序入口類
│ ├──entryformability
│ │ └──EntryFormAbility.ets // 卡片創建,更新,刪除操作類
│ ├──pages
│ │ ├──MovieDetailsPage.ets // 電影詳情頁
│ │ └──MovieListPage.ets // 主頁面
│ ├──view
│ │ ├──MovieDetailsTitle.ets // 電影詳情頭部組件
│ │ ├──MovieItem.ets // 列表item組件
│ │ ├──MovieStarring.ets // 電影主演組件
│ │ ├──MovieStills.ets // 電影劇照組件
│ │ ├──StarsWidget.ets // 電影評分組件
│ │ └──StoryIntroduce.ets // 電影簡介組件
│ └──viewmodel
│ ├──FormBean.ets // 卡片對象
│ ├──FormDataBean.ets // 卡片數據對象
│ └──MovieDataBean.ets // 電影數據對象
├──entry/src/main/js // js代碼區
│ ├──card2x2 // 2x2卡片目錄
│ ├──card2x4 // 2x4卡片目錄
│ └──common // 卡片資源目錄
└──entry/src/main/resources // 資源文件目錄
![搜狗高速瀏覽器截圖20240326151344.png](//file1.elecfans.com/web2/M00/C6/C5/wKgaomYCyYKAZp6HAAB4LWPdpdQ014.jpg)
## 關系型數據庫
元服務卡片需要用數據庫保存不同卡片數據,而且在添加多張卡片情況下,需要保持數據同步刷新。因此需要創建一張表,用于保存卡片信息。
1. 數據庫創建使用的SQLite。
// CommonConstants.ets
// 創建數據庫表結構
static readonly CREATE_TABLE_FORM: string = 'CREATE TABLE IF NOT EXISTS Form ' +
'(id INTEGER PRIMARY KEY AUTOINCREMENT, formId TEXT NOT NULL, formName TEXT NOT NULL, dimension INTEGER)';
2. 在EntryAbility的onCreate方法通過CommonUtils.createRdbStore方法創建數據庫,并創建相應的表。
// EntryAbility.ets
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
...
// 創建數據庫
CommonUtil.createRdbStore(this.context);
}
}
// CommonUtils.ets
import relationalStore from '@ohos.data.relationalStore';
async createRdbStore(context: Context) {
let rdbStore = GlobalContext.getContext().getObject('rdbStore') as relationalStore.RdbStore;
if (this.isEmpty(rdbStore)) {
rdbStore = await relationalStore.getRdbStore(context, CommonConstants.STORE_CONFIG);
if (!this.isEmpty(rdbStore)) {
rdbStore.executeSql(CommonConstants.CREATE_TABLE_FORM).catch((error: Error) = > {
Logger.error(CommonConstants.TAG_COMMON_UTILS, 'executeSql error ' + JSON.stringify(error));
});
GlobalContext.getContext().setObject('rdbStore', rdbStore);
}
}
return rdbStore;
}
## 構建應用頁面
電影卡片應用有兩個頁面,分別是電影列表和電影詳情。
## 電影列表
電影列表采用Column容器嵌套List和自定義組件MovieItem形式完成頁面整體布局,效果如圖所示:
![](//file1.elecfans.com/web2/M00/C8/93/wKgZomYc95GAJr0JAAB7gIkV6B4913.jpg)
// MovieListPage.ets
build() {
Column() {
...
List({ space: StyleConstants.LIST_COMPONENT_SPACE }) {
LazyForEach(this.dataSource, (item: MovieDataBean) = > {
ListItem() {
// 電影item
MovieItem({ movieItem: item });
}
}, (item: MovieDataBean) = > JSON.stringify(item))
}
...
}
...
}
// MovieItem.ets
aboutToAppear() {
if (CommonUtils.isEmpty(this.movieItem)) {
Logger.error(CommonConstants.TAG_MOVIE_ITEM, 'movieItem is null');
return;
}
// 獲取電影索引
this.sort = this.movieItem.sort;
...
}
build() {
Row(){
...
Text($r('app.string.want_to_see'))
...
.onClick(() = > {
router.pushUrl({
url: CommonConstants.SEE_BUTTON_PUSH,
params: {
index: this.sort
}
}).catch((error: Error) = > {
...
});
})
}
...
}
## 電影詳情
電影詳情采用Column容器嵌套自定義組件MovieDetailsTitle、StoryIntroduce、MovieStarring和MovieStills形式完成頁面整體布局,效果如圖所示:
![](//file1.elecfans.com/web2/M00/C9/77/wKgaomYc95GAPidnAACH3mClliI740.jpg)
// MovieDetailPage.ets
aboutToAppear() {
let index: number = 0;
let params = router.getParams() as Record< string, Object >;
if (!CommonUtils.isEmpty(params)) {
index = params.index as number;
} else {
let position = GlobalContext.getContext().getObject('position') as number;
index = position ?? 0;
}
let listData: MovieDataBean[] = CommonUtils.getListData();
if (CommonUtils.isEmptyArr(listData)) {
Logger.error(CommonConstants.TAG_DETAILS_PAGE, 'listData is 0');
return;
}
this.movieData = listData[index];
this.introduction = listData[index].introduction;
}
build() {
Column() {
...
Column() {
// 電影詳情頭部組件
MovieDetailsTitle({
movieDetail: this.movieData
})
// 劇情簡介組件
StoryIntroduce({
introduction: this.introduction
})
}
...
// 電影主演組件
MovieStarring()
// 電影劇照組件
MovieStills()
}
...
}
## 元服務卡片
使用元服務卡片分為四步:創建、初始化、更新、刪除。
### 創建元服務卡片目錄
1. 在main目錄下,點擊鼠標右鍵 > New > Service Widget。
![](//file1.elecfans.com/web2/M00/C8/6F/wKgZomYbz2OAdDzsAADeJtQGk-c457.jpg)
2. 然后選擇第一個選項下面帶有Hello World字樣,點擊下一步Next。
![](//file1.elecfans.com/web2/M00/C8/6F/wKgZomYbz2SAc8ymAABjV3ZW-3g413.jpg)
3. 填寫卡片名字(Service widget name)、卡片介紹(Description)、是否開啟低代碼開發(Enable Super Visual)、開發語言(ArkTS和JS)、支持卡片規格(Support dimension)、關聯表單(Ability name)點擊Finish完成創建。如需創建多個卡片目錄重新按照步驟1執行。
![](//file1.elecfans.com/web2/M00/C8/6F/wKgZomYbz2OAd_d6AABvu7227Bc994.jpg)
4. 創建完卡片后,同級目錄出現js目錄,然后開發者在js目錄下使用hml+css+json開發js卡片頁面。
![](//file1.elecfans.com/web2/M00/C9/56/wKgaomYbz2SARbYQAAAwbXW2TmQ950.jpg)
### 初始化元服務卡片
應用選擇添加元服務卡片到桌面后,在EntryFormAbility的onAddForm方法進行卡片初始化操作,效果如圖所示:
![](//file1.elecfans.com/web2/M00/C8/93/wKgZomYc95GAWiCzAAAzGCnPa84657.jpg)
// EntryFormAbility.ets
onAddForm(want: Want) {
if (want.parameters === undefined) {
return formBindingData.createFormBindingData();
}
let formId: string = want.parameters[CommonConstants.IDENTITY_KEY] as string;
let formName: string = want.parameters[CommonConstants.NAME_KEY] as string;
let dimensionFlag: number = want.parameters[CommonConstants.DIMENSION_KEY] as number;
CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) = > {
let form: FormBean = new FormBean();
form.formId = formId;
form.formName = formName;
form.dimension = dimensionFlag;
CommonUtils.insertForm(form, rdbStore);
}).catch((error: Error) = > {
Logger.error(CommonConstants.TAG_FORM_ABILITY, 'onAddForm create rdb error ' + JSON.stringify(error));
});
let listData: MovieDataBean[] = CommonUtils.getListData();
let formData = CommonUtils.getFormData(listData);
return formBindingData.createFormBindingData(formData);
}
### 更新元服務卡片
1. 初始化加載電影列表布局之前,在MovieListPage的aboutToAppear方法中,通過CommonUtils.startTimer方法開啟定時器,時間到則調用updateMovieCardData方法更新電影卡片數據。
// MovieListPage.ets
aboutToAppear() {
...
// 啟動定時器,每5分鐘更新一次電影卡片數據。
CommonUtils.startTimer();
}
// CommonUtils.ets
startTimer() {
let intervalId = GlobalContext.getContext().getObject('intervalId') as number;
if (this.isEmpty(intervalId)) {
intervalId = setInterval(() = > {
let rdbStore = GlobalContext.getContext().getObject('rdbStore') as relationalStore.RdbStore;
this.updateMovieCardData(rdbStore);
}, CommonConstants.INTERVAL_DELAY_TIME);
}
GlobalContext.getContext().setObject('intervalId', intervalId);
}
// 更新電影卡片數據
updateMovieCardData(rdbStore: relationalStore.RdbStore) {
if (this.isEmpty(rdbStore)) {
Logger.error(CommonConstants.TAG_COMMON_UTILS, 'rdbStore is null');
return;
}
let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates(CommonConstants.TABLE_NAME);
rdbStore.query(predicates).then((resultSet: relationalStore.ResultSet) = > {
if (resultSet.rowCount <= 0) {
Logger.error(CommonConstants.TAG_COMMON_UTILS, 'updateCardMovieData rowCount <= 0');
return;
}
let listData: MovieDataBean[] = this.getListData();
resultSet.goToFirstRow();
do {
let formData = this.getFormData(listData);
let formId: string = resultSet.getString(resultSet.getColumnIndex(CommonConstants.FORM_ID));
formProvider.updateForm(formId, formBindingData.createFormBindingData(formData))
.catch((error: Error) = > {
Logger.error(CommonConstants.TAG_COMMON_UTILS, 'updateForm error ' + JSON.stringify(error));
});
} while (resultSet.goToNextRow());
resultSet.close();
}).catch((error: Error) = > {
Logger.error(CommonConstants.TAG_COMMON_UTILS, 'updateCardMovieData error ' + JSON.stringify(error));
});
2. 通過src/main/resources/base/profile/form_config.json配置文件,根據updateDuration或者scheduledUpdateTime字段配置刷新時間。updateDuration優先級高于scheduledUpdateTime,兩者同時配置時,以updateDuration配置的刷新時間為準。當配置的刷新時間到了,系統調用onUpdateForm方法進行更新。
// form_config.json
{
// 卡片的類名
"name": "card2x2",
// 卡片的描述
"description": "This is a service widget.",
// 卡片對應完整路徑
"src": "./js/card2x2/pages/index/index",
// 定義與顯示窗口相關的配置
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
// 卡片的主題樣式
"colorMode": "auto",
// 是否為默認卡片
"isDefault": true,
// 卡片是否支持周期性刷新
"updateEnabled": true,
// 采用24小時制,精確到分鐘
"scheduledUpdateTime": "00:00",
// 當取值為0時,表示該參數不生效,當取值為正整數N時,表示刷新周期為30N分鐘。
"updateDuration": 1,
// 卡片默認外觀規格
"defaultDimension": "22",
// 卡片支持外觀規格
"supportDimensions": [
"2*2"
]
}
...
// EntryFormAbility.ets
onUpdateForm(formId: string) {
CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) = > {
CommonUtils.updateMovieCardData(rdbStore);
}).catch((error: Error) = > {
...
});
...
}
### 刪除元服務卡片
當用戶需要刪除元服務卡片時,可以在EntryFormAbility的onRemoveForm方法中,通過CommonUtils.deleteFormData方法刪除數據庫中對應的卡片信息。
// EntryFormAbility.ets
onRemoveForm(formId: string) {
CommonUtils.createRdbStore(this.context).then((rdbStore: relationalStore.RdbStore) = > {
// 從數據庫中刪除電影卡片信息
CommonUtils.deleteFormData(formId, rdbStore);
}).catch((error: Error) = > {
...
});
}
// CommonUtils.ets
deleteFormData(formId: string, rdbStore: relationalStore.RdbStore) {
...
let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates(CommonConstants.TABLE_NAME);
predicates.equalTo(CommonConstants.FORM_ID, formId);
rdbStore.delete(predicates).catch((error: Error) = > {
...
});
}
審核編輯 黃宇
-
鴻蒙
+關注
關注
57文章
2307瀏覽量
42738 -
OpenHarmony
+關注
關注
25文章
3658瀏覽量
16146
發布評論請先 登錄
相關推薦
評論