鴻蒙核心技術(shù)##運動開發(fā)## Remote Communication Kit(遠場通信服務(wù))
在之前的文章中,我們詳細介紹了如何封裝一個功能完備的 RCP 網(wǎng)絡(luò)庫,并探討了其核心功能和高級特性。在本篇中,我們將展示如何在鴻蒙運動項目中使用這個網(wǎng)絡(luò)庫來實現(xiàn)具體的網(wǎng)絡(luò)請求功能。
前言
在鴻蒙運動項目中,網(wǎng)絡(luò)請求是實現(xiàn)功能的關(guān)鍵環(huán)節(jié)之一。無論是獲取運動數(shù)據(jù)、同步用戶信息,還是加載運動視頻資源,都需要一個穩(wěn)定、高效且易于使用的網(wǎng)絡(luò)庫。在本篇中,我們將通過實際代碼樣例,展示如何使用封裝好的 RCP 網(wǎng)絡(luò)庫實現(xiàn)這些功能。
一、封裝異常處理
在實際開發(fā)中,異常處理是網(wǎng)絡(luò)請求中不可或缺的一部分。通過自定義異常類,我們可以更好地管理網(wǎng)絡(luò)請求中可能出現(xiàn)的各種錯誤。
(一)自定義異常類
定義了一個 ApiException 類,用于封裝 API 請求中的錯誤信息。
export class ApiException extends Error {
apiCode?: number;
apiMessage?: string;
constructor(apiCode?: number, apiMessage?: string) {
super();
this.name = "ApiException";
this.apiCode = apiCode;
this.apiMessage = apiMessage;
}
}
核心點解析:
-
自定義屬性:
apiCode和apiMessage用于存儲 API 返回的錯誤代碼和錯誤信息。 - 構(gòu)造函數(shù):通過構(gòu)造函數(shù)初始化異常對象,并設(shè)置錯誤代碼和錯誤信息。
二、封裝網(wǎng)絡(luò)請求
為了簡化網(wǎng)絡(luò)請求的實現(xiàn),你封裝了一個 ApiRequest 類,用于統(tǒng)一管理網(wǎng)絡(luò)請求和錯誤處理。
(一)單例模式
ApiRequest 類使用了單例模式,確保全局只有一個實例。
import { DataResult, ErrorCodes, ErrorData, LibToast, NetworkException, SuccessData } from "lib_base";
import { RcpNetworkService } from "lib_base/src/main/ets/utils/rcpnet/RcpService";
import { ApiResult } from "../data/models/ApiResult";
import { ApiException } from "./ApiException";
export interface IApiRequestHandleBusinessError{
handleBusinessError(apiException: ApiException): boolean
}
export class ApiRequest{
private static instance: ApiRequest
static getInstance (): ApiRequest {
if (!ApiRequest.instance) {
ApiRequest.instance = new ApiRequest()
}
return ApiRequest.instance
}
private _net?: RcpNetworkService | undefined;
private _i_api_equest_handle_business_error?: IApiRequestHandleBusinessError | undefined;
public set i_api_equest_handle_business_error(value: IApiRequestHandleBusinessError | undefined) {
this._i_api_equest_handle_business_error = value;
}
public set net(value: RcpNetworkService | undefined) {
this._net = value;
}
public getService() : RcpNetworkService{
return this._net!;
}
}
核心點解析:
-
單例模式:通過
getInstance方法確保ApiRequest的全局唯一性。 -
依賴注入:通過
set方法注入RcpNetworkService和IApiRequestHandleBusinessError,增強類的靈活性。
(二)統(tǒng)一請求方法
ApiRequest 類提供了一個統(tǒng)一的請求方法 remoteApi,用于處理網(wǎng)絡(luò)請求并封裝返回結(jié)果。
export interface IApiRequestHandleBusinessError {
handleBusinessError(apiException: ApiException): boolean;
}
export class ApiRequest {
public static async remoteApi<T>(api:()=>Promise<ApiResult<T>>): Promise<DataResult<ApiResult<T>|null>>{
try{
const data = await api()
if(data.success && data.success){
let bean = new SuccessData<ApiResult<T>>(data)
return bean;
} else {
let bean = ErrorData.fromError(new ApiException(data.code,data.msg) as Error,data.code?.toString(),data.msg)
return bean;
}
}catch (e) {
if(e instanceof NetworkException){
let bean = ErrorData.fromError(e)
//請求被框架取消,客戶端不進入異常處理,避免業(yè)務(wù)彈窗
if(e.code !== ErrorCodes.REQUEST_CANCEL){
LibToast.show(e.message)
}
return bean;
}
throw e as Error
}
}
}
核心點解析:
-
請求執(zhí)行:通過傳入的
api函數(shù)執(zhí)行具體的網(wǎng)絡(luò)請求。 -
成功處理:如果請求成功,返回
SuccessData對象。 -
失敗處理:如果請求失敗,根據(jù)錯誤類型返回
ErrorData對象。 -
網(wǎng)絡(luò)異常處理:捕獲
NetworkException,并根據(jù)錯誤代碼決定是否顯示提示信息。
(三)業(yè)務(wù)邏輯處理
ApiRequest 類還提供了一個 service 方法,用于處理業(yè)務(wù)邏輯和錯誤。
export class ApiRequest {
// ... 其他代碼 ...
public static async service<T>(source:()=>Promise<DataResult<ApiResult<T>|null>>,
request : (data:DataResult<T|null>)=>void,
apiError : (apiError:ErrorData)=>void,
netError? : (netError:ErrorData)=>void,
){
let data = await source();
if(data instanceof SuccessData){
request(data.data)
}else {
let error = data as ErrorData
if(error.error&&error.error instanceof ApiException){
//業(yè)務(wù)異常
if(ApiRequest.instance._i_api_equest_handle_business_error){
ApiRequest.instance._i_api_equest_handle_business_error.handleBusinessError(error.error)
}
apiError(error)
}else {
//網(wǎng)絡(luò)異常
if(netError){
netError(error)
}
}
}
}
}
核心點解析:
-
請求執(zhí)行:通過
source函數(shù)執(zhí)行網(wǎng)絡(luò)請求。 -
成功處理:如果請求成功,調(diào)用
request回調(diào)函數(shù)處理數(shù)據(jù)。 -
錯誤處理:根據(jù)錯誤類型調(diào)用
apiError或netError回調(diào)函數(shù)。 -
業(yè)務(wù)邏輯分離:通過
IApiRequestHandleBusinessError接口處理業(yè)務(wù)邏輯錯誤。
三、封裝公共請求頭
在實際開發(fā)中,許多請求都需要攜帶公共請求頭,例如設(shè)備信息、用戶令牌等。你通過 CommonHeaderInterceptor 類實現(xiàn)了公共請求頭的封裝。
export async function getCommonHeaders(): Promise<Record<string, string>> {
return {
"device": LibDevice.getDeviceInfo(),
"machineCode": await USystem.getUniqueKey(),
"terminalType": "1", // 示例終端類型
"timestamp": new Date().toISOString(),
"versionNumber": LibDevice.getAppVersionCode().toString(),
"osId": Platform.appPlatform, // 示例 osId
"versionCode": LibDevice.getAppVersionName(),
"token": AccountManager.getToken()
};
}
export class CommonHeaderInterceptor implements rcp.Interceptor {
async intercept(context: rcp.RequestContext, next: rcp.RequestHandler): Promise<rcp.Response> {
const commonHeaders = await getCommonHeaders();
const keys = Object.keys(commonHeaders);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (!context.request.headers) {
context.request.headers = {};
}
context.request.headers[key] = commonHeaders[key];
}
return next.handle(context);
}
}
核心點解析:
-
公共頭信息:通過
getCommonHeaders函數(shù)獲取公共頭信息。 -
攔截器實現(xiàn):在
intercept方法中,將公共頭信息添加到請求頭中。 - 動態(tài)添加:通過循環(huán)動態(tài)添加公共頭信息,確保每個請求都攜帶必要的信息。
四、封裝響應(yīng)轉(zhuǎn)換器
為了更好地處理響應(yīng)數(shù)據(jù),封裝一個 CommonTextResponseConverter 類,用于處理響應(yīng)內(nèi)容。
export class CommonTextResponseConverter extends TextResponseConverter {
convert(response: rcp.Response): string | object | null {
if (response.toJSON()) {
return response.toJSON();
} else {
return super.convert(response);
}
}
}
核心點解析:
- JSON 轉(zhuǎn)換:優(yōu)先嘗試將響應(yīng)內(nèi)容轉(zhuǎn)換為 JSON 格式。
-
回退處理:如果無法轉(zhuǎn)換為 JSON,調(diào)用父類的
convert方法處理響應(yīng)內(nèi)容。
五、實際應(yīng)用案例:獲取運動數(shù)據(jù)
假設(shè)我們需要從服務(wù)器獲取用戶的運動數(shù)據(jù),例如運動記錄、運動計劃等。我們將通過封裝好的 RCP 網(wǎng)絡(luò)庫來實現(xiàn)這一功能。
(一)封裝請求方法
export async function getAllLookSubjectList(params: Record<"parentId", string>, requestKeyFun?: (str: string) => void): Promise<ApiResult<Subject[]>> {
return ApiRequest.getInstance().getService().request<ApiResult<Subject[]>>>({
act: AllLOOK_SUBJECT_LIST,
method: RequestMethod.POST,
contentType: RcpContentType.JSON,
content: params
}, requestKeyFun);
}
核心點解析:
-
請求配置:通過
RequestOptions配置請求的基本信息,如 API 路徑、請求方法和內(nèi)容類型。 -
請求發(fā)送:使用
ApiRequest.getInstance().getService().request方法發(fā)送請求。 -
回調(diào)函數(shù):通過
requestKeyFun提供請求鍵值,用于取消請求等操作。
(二)調(diào)用請求方法
在實際的頁面或組件中,我們可以調(diào)用封裝好的請求方法來獲取運動數(shù)據(jù)。
aboutToAppear(): void {
super.aboutToAppear();
this.showLoading();
ApiRequest.service<Subject[]>(() => {
return LookResponsitory.getInstance().getAllLookSubjectList("1", (requestKey) => {
if (requestKey) {
this.addRequestId(requestKey);
}
});
}, (data) => {
this.hideLoading();
if (data.data && data.data.length > 0) {
this.tabs = data.data;
} else {
this.setDefalutTab();
}
}, (apiError) => {
this.hideLoading();
this.setDefalutTab();
// 業(yè)務(wù)異常
// LibToast.show(apiError.message ?? "獲取異常");
}, () => {
this.hideLoading();
this.setDefalutTab();
// 網(wǎng)絡(luò)等異常
// LibToast.show("網(wǎng)絡(luò)異常");
});
}
核心點解析:
-
請求執(zhí)行:通過
ApiRequest.service方法執(zhí)行網(wǎng)絡(luò)請求。 - 成功處理:如果請求成功,處理返回的數(shù)據(jù)。
- 錯誤處理:根據(jù)錯誤類型調(diào)用相應(yīng)的回調(diào)函數(shù)處理錯誤。
- 加載狀態(tài):在請求開始時顯示加載狀態(tài),在請求結(jié)束時隱藏加載狀態(tài)。
六、總結(jié)
通過本篇的實戰(zhàn)案例,我們展示了如何使用封裝好的 RCP 網(wǎng)絡(luò)庫實現(xiàn)具體的網(wǎng)絡(luò)請求功能。通過定義異常類、封裝請求方法、處理公共請求頭和響應(yīng)轉(zhuǎn)換器,以及實現(xiàn)具體的請求邏輯,我們能夠高效地完成網(wǎng)絡(luò)請求任務(wù)。封裝好的網(wǎng)絡(luò)庫不僅提供了基本的請求和響應(yīng)處理功能,還具備錯誤處理、日志記錄、會話管理和網(wǎng)絡(luò)狀態(tài)檢測等高級特性,能夠滿足大多數(shù)網(wǎng)絡(luò)請求場景的需求。