RCP下载文件，会重复回调同一个进度，如何解决
=======================

#### 问题现象

使用RCP接口下载文件，onDownloadProgress会重复回调同一个进度，导致业务逻辑重复执行。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/0f/v3/xAp6MeWZTcmQX1CeCQ6QYg/zh-cn_image_0000002628612488.png?HW-CC-KV=V1&HW-CC-Date=20260709T134214Z&HW-CC-Expire=86400&HW-CC-Sign=A7C6000FA0E19E340544CE1C0B5159E599028C7CB5F06DAF8B6E0B0026D7BB44 "点击放大")

#### 背景知识

*   通过[downloadToFile](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/remote-communication-rcp#section16508121443318)接口下载文件，会在[onDownloadProgress](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/remote-communication-rcp#section832314187551)回调中返回当前下载进度，该接口需要配置ohos.permission.INTERNET权限，如果使用[PathPreference](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/remote-communication-rcp#section828055885811)的'cellular'模式，则额外需要ohos.permission.GET\_NETWORK\_INFO权限。
*   [onHeaderReceive](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/remote-communication-rcp#section13232139165012)回调中可以通过content-length获取下载文件的总长度。
*   [onDataReceive](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/remote-communication-rcp#section9264115918536)回调可以获取到当前返回内容的长度。

#### 解决方案

*   **方案一**：
    
    5.0系统版本，onDownloadProgress存在冗余回调bug，5.1及以上系统版本已经修复该问题，可升级系统至5.1以上版本。
    
*   **方案二**：
    
    业务侧可通过文件总大小和当前已接收的文件大小计算下载进度：
    
    import rcp from '@hms.collaboration.rcp';
    
    @Entry
    @Component
    struct Index {
      @State curValue: number = 0;
      @State totalData: number = 0;
      @State progress: number = 0;
      @State enableDownload: boolean = true;
     _ // 需要替换成实际的url_
      downloadUrl: string = '';
    
      build() {
        Column({ space: 20 }) {
          Progress({ value: this.curValue, total: this.totalData, type: ProgressType.Capsule })
            .width(200)
            .height(40)
            .style({ enableSmoothEffect: true, content: this.progress.toFixed(2) + '%' });
    
          Button('点击开始下载')
            .onClick(() => {
              this.enableDownload = false;
              this.curValue = 0;
              this.progress = 0;
         _     // 下载文件数据_
              this.startDownload(this.downloadUrl);
            })
            .enabled(this.enableDownload);
        }
        .justifyContent(FlexAlign.Center)
        .height('100%')
        .width('100%');
      }
    
     _ // 下载文件_
      startDownload(url: string) {
       _ // 响应数据处理_
        const eventsHandler: rcp.HttpEventsHandler = {
          onHeaderReceive: (headers: rcp.ResponseHeaders) => {
            this.totalData = Number(headers\['content-length'\]);
          },
          onDataReceive: (incomingData: ArrayBuffer) => {
            this.curValue += incomingData.byteLength;
            this.progress = (this.curValue / this.totalData) \* 100;
            console.info('Download progress:', this.curValue, 'of', this.totalData);
          },
        _  // 数据完成接收监听_
          onDataEnd: () => {
            console.info('Data transfer complete');
            this.enableDownload = true;
          },
        _  // 取消数据接收监听_
          onCanceled: () => {
            console.info('Request/response canceled');
          },
        };
       _ // 建立session对象_
        let session = rcp.createSession({
          requestConfiguration: {
            tracing: {
              verbose: true,
              collectTimeInfo: true,
              httpEventsHandler: eventsHandler,
            }
          }
        });
        session.downloadToFile(url, {
          kind: 'file',
          file: \`${this.getUIContext().getHostContext()?.filesDir}/test\`,
        }).then((response) => {
          console.info(\`Download result ${response.toJSON()}\`);
          session.close();
        }).catch((err: Error) => {
          console.error(\`${JSON.stringify(err)}\`);
          session.close();
        });
      }
    }