# empty_rcp_codelab **Repository Path**: maosiping/empty_rcp_codelab ## Basic Information - **Project Name**: empty_rcp_codelab - **Description**: Rcp demo which need the developers to fill some code. - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-06-20 - **Last Updated**: 2024-06-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 高性能网络资源加载 ### 介绍 [RemoteCommunicationKit](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/remote-communication-kit-guide-V5)提供设备远距离通信能力,应用可以使用RemoteCommunicationKit实现更丰富、低代码和场景化的网络请求与响应。 您将通过本案例实现一个网络加载图文资源的应用。 在实现例1中,这个应用支持简单的网络资源加载功能,您可以用它实现图片与文字的加载与展示; 在实现例2中,这个应用支持拦截器功能,使用拦截器可以方便的对HTTP的请求与响应进行修改,您可以借助拦截器修改网络请求的URL实现请求更轻量的图片资源; 在实现例3中,这个应用支持跟随图文滑动位置动态加载与取消网络资源的能力,基于此您可以实现图文滑动场景高性能流畅加载的极致体验。 ### 效果预览 | 实施例1 - 基本图文加载 | 实施例2 - 拦截器 | 实施例3 - 网络图文滑动访问 | |--------------------------------------------------------------------------|-------------------------------------------|----------------------------------------------------------| | ![image](screenshots/devices/TAB1-GET-TEXT.jpg) | ![image](screenshots/devices/TAB1-GET-IMAGE-2-with-interceptors.jpg) | ![image](screenshots/devices/TAB2-NONE-WHITE-BLOCKS.jpg) | ### 使用说明 1. 启动应用,进入“RCP Demo”页签。 2. 点击“GET text”按钮,可以从服务器获取到文字信息“Welcome to HDC 2024!”。 3. 点击“GET image”按钮,可以从服务器获取到高分辨率图片。 4. 打开“Simulate slow network”按钮,之后再点击“Get image”按钮,可以从服务器获取到低分辨率图片。 5. 在顶部切换到“Prefetch Demo”页签,您可以体验流畅的网络图文访问界面。 ### 工程目录 ``` ├──entry/src/main/ets // 代码区 │ ├──ets │ │ ├──prefetchdemo // 网络图文加载功能 │ │ │ └──DataSourcePrefetchingRCP.ets // 实现例3:基于RemoteCommunicationKit的网络加载实现 | | | └──ListItemComponent.ets // 列表详情组件 | | | └──PageViewModel.ets // 列表信息生成器 | | | └──PrefetchDemoComponent.ets // 网络图文列表组件 | | | └──SongInfoItem.ets // 图文字段变量 | | | └──SongInforProvider.ets // 图文信息声 │ │ └──rcpdemo │ │ └──Interceptors.ets // 实现例2:拦截器 | | └──NetworkStateSimulator.ets // 模拟网络状态 | | |──RCPDemoComponents.ets // 实现例1:基本文字加载 │ └──EntryAbility.ets | └──MainPage.ets │ ├──resources // 资源文件夹 ├──lib_prefetch // 图文滑动预加载算法 ``` ### 相关权限 应用需要访问互联网,需要使用网络权限。 ``` ohos.permission.INTERNET ``` ### 依赖 该应用依赖连接网络服务器。 为了方便您体验RemoteCommunicationKit,我们为您准备临时网络服务器,在各实施例中,我们直接声明您需要访问的URL,您可以直接访问代码中的地址实现预期效果。 **请注意:** 该应用中的临时网络服务器仅用于在当前codelab中使用和体验RemoteCommunicationKit,计划将在2024年7月择期关闭。 ### 约束与限制 1. 本示例仅支持标准系统上运行,支持设备:华为手机。 2. HarmonyOS系统:HarmonyOS NEXT Developer Beta1及以上。 3. DevEco Studio版本:DevEco Studio NEXT Developer Beta1及以上。 4. HarmonyOS SDK版本:HarmonyOS NEXT Developer Beta1 SDK及以上。 ### Codelab挑战步骤 ### 介绍 [RemoteCommunicationKit](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/remote-communication-kit-guide-V5)是全新的场景化网络协议框架。 | RemoteCommunicationKit架构 | | :-: | ![image](screenshots/diagrams/RCP-high-level-design.PNG) | RemoteCommunicationKit主要特性如下: - 基于Session来处理多个具有共享配置的请求。 - 高度可定制的API:可链接的拦截器,验证器等。使用拦截器实现与业务逻辑分离的辅助操作(基于过滤器的日志记录,身份验证,缓存,cookie处理等)。 - 支持请求/响应数据的扩展格式:字符串,对象,二进制,文件,流,回调,multipart表单。 - 支持自定义证书验证和代理证书(以及SSL pinning)。 - 高级性能调度:取消请求,限制同时连接数,自动选择HTTP版本,为高工作负载启用多线程。 ### 您将学到 1. 使用声明式编程风格发送HTTP请求,接收HTTP响应。 2. 创建典型的HTTP会话配置:超时设置、证书验证等。 3. 取消传输层HTTP资源加载。 4. 使用拦截器对HTTP请求进行后处理,并对HTTP响应进行预处理,从而方便、透明地实现业务逻辑。 ### 开发准备 1. 准备DevEco Studio。 2. 打开项目。 3. 等待项目同步结束。 4. 为应用签名。 5. 编译和运行应用,点击`Run` > `Run ‘entry’`。 6. 在“RCP Demo”标签中,点击“GET text”按钮、“GET image”按钮。 7. 在“Prefetch Demo”标签中,尝试滑动屏幕。 | Step 2 | Step 4 | Step 6 | Step 7 | | :-: | :-: | :-: | :-: | | ![image](screenshots/deveco/Mainpage.png) | ![image](screenshots/deveco/Sign-in-config.png) | ![image](screenshots/devices/TAB1-EMPTY.jpg) | ![image](screenshots/devices/TAB2-WITH-WHITE-BLOCKS.jpg) | ### 开发过程 #### 任务1 基本图文加载 1. 打开文件 `RCPDemoComponent.ets`,找到`getText`方法 2. 实现`getText`方法的空白部分,以便它可以从`https://1.95.54.71/welcome` URL获取数据,并将结果保存在`responseText`中。您可以使用以下文档作为参考[远程通信工具包/基本功能](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/remote-communication-basic-ability-V5) 3. 编译运行应用,点击“GET text”按钮,您将看到文本区域显示文字。 | 任务1截图 | | :-: | | | #### 任务2 实现图片下载 1. 打开文件`RCPDemoComponent.ets`文件,找到`getImage`方法 2. 实现`getImage`方法中空白的部分,使它能够访问指定的URL,获取结果显示在`pathToImage`中。 3. 编译运行应用,点击`GET image`按钮,您将看到图片区域显示图片。 参考代码如下: ```typescript private async getImage() { this.isImageDownloaded = false; const networkStateSimulator = new NetworkStateSimulator(); const session = rcp.createSession({ requestConfiguration: { transfer: { timeout: { connectMs: 5 * 1000, }, }, }, interceptors: [ ], }); try { if (this.simulateSlowNetwork) { networkStateSimulator.simulateSlowNetwork(); } else { networkStateSimulator.simulateFastNetwork(); } const request = new rcp.Request('https://1.95.54.71/Panda.jpg', 'GET'); request.destination = { kind: 'file', file: this.pathToImage }; request.configuration = { security: { remoteValidation: 'skip', }, tracing: { collectTimeInfo: true, }, }; const response = await session.fetch(request); this.logResponse(response); const isFileCreated = await fileIo.access(this.pathToImage); if (response.statusCode === 200 && isFileCreated) { this.isImageDownloaded = true; } } catch (e) { this.logError(e) } finally { session.close(); } } ``` #### 任务3 实现拦截器 拦截器应用提供了便利的修改请求、响应的方式,在RemoteCommunicationKit中,您可以创建拦截器链,按需定制一组拦截器堆您的网络请求/响应进行修改。 | RemoteCommunicationKit中拦截器工作机制 | |:-----------------------------------------------:| | ![image](screenshots/diagrams/Interceptors.PNG) | 该任务中,您将通过以下步骤实现拦截器。 1. 打开`Interceptors.ets`文件, 找到`RequestUrlChangeInterceptor`和`ResponseHeaderRemoveInterceptor`实现, 您需要实现请求拦截器`RequestUrlChangeInterceptor`: - `RequestUrlChangeInterceptor`实现请求拦截,例如当网络质量变化时,调整请求资源的大小。 - `ResponseHeaderRemoveInterceptor` 实现响应拦截,它可以在响应返回给应用前检查和修改服务器的请求头。 2. 在`RCPDemoComponent.ets`中,您可以看到`getImage`方法中的session使能了步骤1中的拦截器。 | 拦截器使能的办法 | |:----------------------------------------------------------------------------:| | ![image](screenshots/diagrams/Add-interceptors-to-session-configuration.PNG) | 3. 实现拦截器
任务3答案 ```typescript if (context.request.method === 'GET' && !this.networkQualityProvider.isNetworkFast()) { this.logger.log('[RequestUrlChangeInterceptor]: Slow network is detected'); const parts = context.request.url.pathname.split('.'); if (parts.length === 2) { const changed = url.URL.parseURL(context.request.url.href); changed.pathname = parts[0] + '_small.' + parts[1]; this.logger.log(`[RequestUrlChangeInterceptor]: Replace URL from "${context.request.url.href}" to "${changed}"`); context.request.url = changed; } } else { this.logger.log('[RequestUrlChangeInterceptor]: Network is fast'); } ```
4. 编译运行应用,在点击`Simulate slow network`开关打开后点击`Get Image`,如果您的拦截器实现正确,图片资源将替换为低分辨率图片。 | 实现效果示意 | |:------------------------------------------------------------------------------:| | | #### 任务4 实现图文请求预加载和取消 1. 打开`DataSourcePrefetchingRCP.ets`文件,实现`prefetch`方法,该方法将页面的albumUrl资源提前下载并缓存到本地文件,使跟随页面滑动时网络图片提前加载。 参考代码如下: ```typescript async prefetch(index: number): Promise { PREFETCH_ENABLED = true; if (this.requestsInFlight.hasKey(index)) { throw new Error('Already being prefetched'); } const item = this.data[index]; if (item.cachedImage) { return; } const request = new rcp.Request(item.albumUrl, 'GET'); this.requestsInFlight.set(index, request); try { const response = await this.session.fetch(request); if (response.statusCode !== 200 || !response.body) { throw new Error('Bad response'); } item.cachedImage = await this.cache(item.songId, response.body); this.requestsInFlight.remove(index); } catch (e) { if (e.code !== CANCEL_CODE) { item.cachedImage = IMAGE_UNAVAILABLE; this.requestsInFlight.remove(index); } throw e as Error; } ``` 2. 打开`DataSourcePrefetchingRCP.ets`文件,实现`cancel`方法,该方法可以取消正在下载的网络资源,使不必要的场景下取消网络请求。 参考代码如下: ```typescript cancel(index: number) { if (this.requestsInFlight.hasKey(index)) { const request = this.requestsInFlight.get(index); this.session.cancel(request); this.requestsInFlight.remove(index); } } ``` 3. 编译运行应用,查看效果:图片加载更为流畅丝滑。 | Screenshot of app for steps 3 | | :-: | | | ### 附件
任务1答案 ```typescript private async getText() { this.responseText = ''; const session = rcp.createSession({ requestConfiguration: { transfer: { timeout: { connectMs: 5 * 1000 }, }, security: { remoteValidation: 'skip' }, }, }); try { const response = await session.get('https://1.95.54.71/welcome'); this.logResponse(response); const body = response.toString(); if (response.statusCode === 200 && body !== null && body.length > 0) { this.responseText = body; } } catch (e) { this.logError(e); } finally { session.close(); } } ```