HarmonyOS应用开发之源-07-从加载分页列表探索鸿蒙网络数据技术

395 阅读6分钟

系列文章目录

HarmonyOS应用开发之道:掌握未来,领略技术的魅力-01-ArkTS基础知识

HarmonyOS应用开发全攻略:从入门到精通-02-程序框架UIAbility、启动模式与路由跳转

HarmonyOS应用开发系列:探索未来的技术前沿-03-基础组件-让我们来码出复杂酷炫的UI

HarmonyOS应用开发指南:为未来做好准备-04-组件状态管理

HarmonyOS应用开发必修课-05-让我们的界面动起来!- 显示动画与属性动画

HarmonyOS应用开发探索之旅:探索未来的技术前沿-06-炫酷的转场动画

HarmonyOS应用开发之源-07-从加载分页列表探索鸿蒙网络数据技术

前言

中间隔了好久没有更新HarmonyOS系列的文章了,今天更新一节HTTP网络请求相关的Demo分析,然后我们可以利用手里的OpenApi设计我们自己的APP来对表Android、iOS以及跨平台技术开发的APP了,对比下实现效果、丝滑度以及我们实际开发中的真实感觉,相信你心中会有一个客观的打分。


本节Demo实现效果:

01.png 02.png 03.png 04.png

一、HTTP请求

HTTP数据请求功能主要由http模块提供,包括发起请求、中断请求、订阅/取消订阅HTTP Response Header 事件等。

在进行网络请求前,您需要在module.json5文件中申明网络访问权限。

{
    "module" : {
        "requestPermissions":[
           {
             "name": "ohos.permission.INTERNET"
           }
        ]
    }
}

1. 导入http模块。

    import http from '@ohos.net.http';

2. 创建httpRequest对象。

使用createHttp()创建一个httpRequest对象,里面包括常用的一些网络请求方法,比如requestdestroyon('headerReceive')等。

let httpRequest = http.createHttp();

需要注意的是每一个httpRequest对象对应一个http请求任务,不可复用。

3. 订阅请求头(可选)。

用于订阅http响应头,此接口会比request请求先返回,可以根据业务需要订阅此消息。

httpRequest.on('headersReceive', (header) => {
    console.info('header: ' + JSON.stringify(header));
});

4. 发起http请求。

http模块支持常用的POSTGET等方法,封装在RequestMethod中。调用request方法发起网络请求,需要传入两个参数。第一个是请求的url地址,第二个是可选参数,类型为HttpRequestOptions,用于定义可选参数的类型和取值范围,包含请求方式、连接超时时间、请求头字段等。

5、GET请求

使用Get请求,参数内容需要拼接到URL中进行发送,如下示例中在url后面拼接了两个自定义参数,分别命名为param1和param2,值分别为value1和value2:

let url= "https://EXAMPLE_URL?param1=v1&param2=v2";
let promise = httpRequest.request(
  // 请求url地址
  url,
  {
    // 请求方式
    method: http.RequestMethod.GET,
    // 可选,默认为60s
    connectTimeout: 60000,
    // 可选,默认为60s
    readTimeout: 60000,
    // 开发者根据自身业务需要添加header字段
    header: {
      'Content-Type': 'application/json'
    }
  });

6、POST请求

POST请求参数需要添加到extraData里面,如下示例中在extraData里面定义添加了两个自定义参数param1和param2,值分别为value1和value2:

let url = "https://EXAMPLE_URL";
let promise = httpRequest.request(
  // 请求url地址
  url,
  {
    // 请求方式
    method: http.RequestMethod.POST,
    // 请求的额外数据。
    extraData: {
      "param1": "value1",
      "param2": "value2",
    },
    // 可选,默认为60s
    connectTimeout: 60000,
    // 可选,默认为60s
    readTimeout: 60000,
    // 开发者根据自身业务需要添加header字段
    header: {
      'Content-Type': 'application/json'
    }
  });

7、处理响应结果

data为网络请求返回的结果,err为请求异常时返回的结果。data的类型为HttpResponse。

promise.then((data) => { 
  if (data.responseCode === http.ResponseCode.OK) {
    console.info('Result:' + data.result);
    console.info('code:' + data.responseCode);
  }
}).catch((err) => {
  console.info('error:' + JSON.stringify(err));
});
  • 其中data.responseCode为http请求返回的状态码,如果状态码为http.ResponseCode.OK(即200),则表示请求成功,更多状态码可以在ResponseCode中查看。
  • data.result为服务器返回的业务数据,开发者可以根据自身业务场景解析此数据。

二、Demo演示

1、效果图

1234
01.png02.png03.png04.png

2、ArticleItem代码

import { WanArticleBean } from '../common/bean/WanArticleBean'
import prompt from '@system.prompt';
import router from '@ohos.router';
import CommonConstants from '../common/constants/CommonConstants';
import Logger from '../common/utils/Logger';

@Component
export default struct ArticleItem {
  private articleData: WanArticleBean;
  private index: number;

  showToast(message: string) {
    prompt.showToast({
      message: message
    })
  }

  build() {
    Column() {
      Row() {
        Text((this.articleData.tags != null && this.articleData.tags.length > 0) ? this.articleData.tags[0].name : '站内')
          .fontSize('10fp')
          .fontColor(Color.White)
          .textAlign(TextAlign.Center)
          .border({ width: 1 })
          .backgroundColor(Color.Red)
          .borderColor(Color.Red)
          .borderRadius(5)
          .padding({ left: 3, right: 3, top: 1, bottom: 1 })

        Blank()

        Text('发布时间:' + this.articleData.niceDate)
          .fontSize('10fp')
      }
      .width('100%')

      Text(this.articleData.title)
        .width('100%')
        .fontSize('16fp')
        .fontColor(Color.Black)
        .maxLines(2)
        .margin({ top: 8, bottom: 8 })
        .textOverflow({ overflow: TextOverflow.Ellipsis })

      Row() {
        Text('No.' + (this.index + 1) + ' ')
          .fontColor(Color.Red)
          .fontSize('14fp')
          .fontWeight(FontWeight.Bold)

        Text(this.articleData.superChapterName)
          .fontColor(Color.Black)
          .fontSize('14fp')

        Text('·')
          .fontColor(Color.Red)
          .margin({ left: 3, right: 3 })

        Text(this.articleData.chapterName)
          .fontColor(Color.Black)
          .fontSize('14fp')

        Blank().layoutWeight(1)

        Text('❤  ' + (this.articleData.author != null ? this.articleData.author : 'author'))
          .fontColor(Color.Blue)
          .fontSize('14fp')
      }
      .width('100%')
    }
    .onClick(() => {
      this.showToast(this.articleData.title)
      router.pushUrl({
        url: CommonConstants.ARTICLE_DETAIL_PAGE,
        params: {
          // linkUrl: this.articleData.link
          articleData: this.articleData
        }
      }).catch((error) => {
        Logger.error('ArticlePage', 'Error:' + JSON.stringify(error))
      })
    })
    .padding('10vp')
    .width('100%')
    .borderRadius('10vp')
    .backgroundColor($r('app.color.start_window_background'))
  }
}

3、ArticlePage代码:

import { WanArticleBean } from '../common/bean/WanArticleBean';
import CommonConstants, { PageState, WanAndroidApiService } from '../common/constants/CommonConstants';
import WanArticleViewModel from '../viewmodel/WanArticleViewModel';
import promptAction from '@ohos.promptAction';
import { ArticlePageListBean } from '../common/bean/ArticlePageListBean';
import ArticleItem from './ArticleItem';
import { WanBannerBean } from '../common/bean/WanBannerBean';
import prompt from '@system.prompt';
import Logger from '../common/utils/Logger';
import router from '@ohos.router';

@Component
export default struct ArticlePage {
  // 数据源
  @State articleListData: Array<WanArticleBean> = [];
  // 当前页码 ArticleList第一页起始为0
  @State currentPage: number = CommonConstants.FIRST_PAGE;
  // 每页请求数量
  @State pageSize: number = CommonConstants.PAGE_SIZE;
  // 请求状态
  @State pageState: number = PageState.Loading;
  // 是否还能加载更多
  @State canLoadMore: boolean = true;
  // 是否正在刷新
  @State isRefreshing: boolean = false;
  // 是否正在刷新2
  @State isRefreshingFromButton: boolean = false;
  // 是否开始加载下一页
  @State isLoadMore: boolean = false;
  // List滑动监听-需绑定列表或宫格组件
  private scroller: Scroller = new Scroller();
  // 是否显示悬浮Button,初始状态不显示
  @State isShowFloatingButton: boolean = false;

  // Swiper控制器
  private swiperController: SwiperController = new SwiperController();

  // Banner数据
  private wanHomeBannerList: Array<WanBannerBean> = [];
  // Banner跳转组装数据
  private articleData: WanArticleBean = new WanArticleBean();

  // 自定义方式:完全自定义转场过程的效果
  @State scale1: number = 1
  @State opacity1: number = 1

  /**
   * 自定义方式:完全自定义转场过程的效果
   */
  pageTransition() {
    // 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0% -- 100%)
    PageTransitionEnter({ duration: 1200, curve: Curve.Linear })
      .onEnter((type: RouteType, progress: number) => {
        this.scale1 = 1
        this.opacity1 = progress
      })
    // 退场过程中会逐帧触发onExit回调,入参为动效的归一化进度(0% -- 100%)
    PageTransitionExit({ duration: 1500, curve: Curve.Ease })
      .onExit((type: RouteType, progress: number) => {
        this.scale1 = 1 - progress
        this.opacity1 = 1
      })
  }

  /**
   * 请求列表数据
   */
  getWanArticleList() {
    if (this.isRefreshing) {
      // 刷新请偶第一页数据
      // this.currentPage = 0;
      this.currentPage = CommonConstants.TEST_FIRST_PAGE;
    }

    if (this.isRefreshingFromButton) {
      // 刷新请偶第一页数据
      // this.currentPage = 0;
      this.currentPage = CommonConstants.TEST_FIRST_PAGE;
    }

    if (this.isLoadMore) {
      // 加载下一页
      this.currentPage++;
    }

    // 增加耗时
    setTimeout(() => {
      WanArticleViewModel.getWanArticleList(this.currentPage, this.pageSize, WanAndroidApiService.HOME_ARTICLE_LIST)
        .then((data: ArticlePageListBean) => {
          if (this.isRefreshing || this.currentPage === CommonConstants.TEST_FIRST_PAGE) {
            // 赋值
            this.articleListData = data.datas;
            promptAction.showToast({ message: 'Loading ' + this.currentPage })
          } else {
            // 赋值
            // this.articleListData = data.datas;
            this.articleListData = this.articleListData.concat(data.datas);
            promptAction.showToast({ message: 'Loading ' + this.currentPage })
          }

          // 如果是悬浮按钮返回第一页,请求成功后修改状态,且将List滑动到顶部
          if (this.isRefreshingFromButton) {
            this.isRefreshingFromButton = false;
            this.scroller.scrollToIndex(0)
          }

          // 判断是否是最后一页
          // 接口中有个字段over为true代表没有更多数据了
          // 这里使用通用的方法,判断当前请求页返回数据数量是否小于每页数量
          // 如果等于每页请求数量,则还有更多数据,否则当前页即为最后一页
          if (data.datas.length === this.pageSize) {
            this.canLoadMore = true;
          } else {
            this.canLoadMore = false;
          }

          // 请求成功状态更新
          this.pageState = PageState.Success;
          // 停止加载更多
          this.isLoadMore = false;
          // 停止刷新第一页数据
          this.isRefreshing = false;
        }).catch((error: string | Resource) => {
        // 请求失败状态更新
        this.pageState = PageState.Fail;
        // 提示Toast
        promptAction.showToast({
          message: error,
          duration: CommonConstants.ANIMATION_DURATION
        });
      })
    }, 1000)
  }

  getWanHomeBannerList() {
    WanArticleViewModel.getWanHomeBanner().then((data: WanBannerBean[]) => {
      // 赋值
      this.wanHomeBannerList = data;
    }).catch((error: string | Resource) => {
      // 请求失败状态更新
      // 提示Toast
      promptAction.showToast({
        message: error,
        duration: CommonConstants.ANIMATION_DURATION
      });
    })
  }

  aboutToAppear() {
    // 请求列表数据
    this.getWanArticleList()
    // 请求Banner数据
    //this.studentList2 = DataModel.getStudentList2();
    this.getWanHomeBannerList();
  }

  @Builder LoadingComponent() {
    Row() {
      LoadingProgress().width(30).height(30)
      Blank().width(10)
      Text('Loading~').fontSize('16vp')
    }
    .margin('30vp')
    .justifyContent(FlexAlign.Center)
  }

  @Builder ClickLoadMoreComponent() {
    Text('---点击加载更多---')
      .fontSize('16vp')
      .margin('30vp')
      .onClick(() => {
        this.isLoadMore = true;
        this.getWanArticleList()
      })
  }

  @Builder LoadMoreAndEnd() {
    Column() {
      if (this.canLoadMore) {
        if (this.isLoadMore) {
          // 加载更多组件
          this.LoadingComponent();
        } else {
          // 点击加载下一页
          this.ClickLoadMoreComponent();
        }
      } else {
        Text('---没有更多了---').fontSize('16vp').margin('30vp')
      }
    }
    .width('100%')
  }

  @Builder ArticleListComponent() {
    List({ space: 16, scroller: this.scroller }) {
      // HomeBanner-Swiper可以不包含在ListItem中
      this.HomeBanner(this.wanHomeBannerList)

      ForEach(this.articleListData, (item: WanArticleBean, index: number) => {
        ListItem() {
          ArticleItem({ articleData: item, index: index })
        }
        .padding({ left: '16vp', right: 16 })
      }, (item, index) => JSON.stringify(item) + index)

      ListItem() {
        this.LoadMoreAndEnd();
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.page_background'))
    // .padding({ left: '16vp', right: 16 })
    .divider({ strokeWidth: 0.1, color: Color.Red })
    .onScrollStart(() => {
      // List滑动时不显示悬浮按钮
      this.isShowFloatingButton = false;
    })
    .onScrollStop(() => {
      // List停止滑动时不显示悬浮按钮
      this.isShowFloatingButton = true;
    })
  }

  @Builder ReloadPageButton() {
    Button() {
      Image($r('app.media.ic_refresh'))
        .rotate({ angle: 90 })
        .width(30)
        .height(30)
    }
    .backgroundColor(Color.Yellow)
    .border({ width: 1 })
    .borderColor(Color.Blue)
    .borderStyle(BorderStyle.Dotted)
    .width(35)
    .height(35)
    .position({ x: '80%', y: '70%' })
    .shadow({ radius: 10 })
    .onClick(() => {
      this.pageState = PageState.Loading;
      this.isRefreshing = true;
      this.getWanArticleList();
    })
  }

  @Builder LoadFirstPageButton() {
    Button() {
      Image($r('app.media.ic_back'))
        .rotate({ angle: 90 })
        .width(30)
        .height(30)
    }
    .backgroundColor(Color.Red)
    .border({ width: 1 })
    .borderColor(Color.Blue)
    .borderStyle(BorderStyle.Dotted)
    .width(35)
    .height(35)
    .position({ x: '80%', y: '80%' })
    .shadow({ radius: 10 })
    .onClick(() => {
      // if (this.currentPage > 0) {
      if (this.currentPage > CommonConstants.TEST_FIRST_PAGE) {
        // 不与Refresh组件联动
        this.isRefreshingFromButton = true;
        this.getWanArticleList();
      } else {
        promptAction.showToast({ message: '当前已经是第一页啦~' })
      }
    })
  }

  @Builder LoadNextPageButton() {
    Button() {
      Image($r('app.media.ic_back'))
        .rotate({ angle: -90 })
        .width(30)
        .height(30)
    }
    .backgroundColor(Color.Red)
    .border({ width: 1 })
    .borderColor(Color.Yellow)
    .borderStyle(BorderStyle.Dashed)
    .width(35)
    .height(35)
    .position({ x: '80%', y: '90%' })
    .shadow({ radius: 10 })
    .onClick(() => {
      if (this.canLoadMore === false) {
        promptAction.showToast({ message: '没有更多数据啦~' })
      } else {
        this.isLoadMore = true;
        this.getWanArticleList()
      }
    })
  }

  /**
   * Banner
   */
  @Builder HomeBanner(dataList: Array<WanBannerBean>) {
    Swiper(this.swiperController) {
      ForEach(dataList, (item: WanBannerBean) => {
        RelativeContainer() {
          Image(item.imagePath)
            .borderRadius($r('app.float.home_swiper_borderRadius'))
            .width('100%')
            .height('100%')
            .objectFit(ImageFit.Fill)
            .onClick(() => {
              // 组装数据
              this.articleData.link = item.url;
              this.articleData.title = item.title;
              this.articleData.author = '站内';

              router.pushUrl({
                url: CommonConstants.ARTICLE_DETAIL_PAGE,
                params: {
                  articleData: this.articleData
                }
              }).catch((error) => {
                Logger.error('ArticlePage', 'Error:' + JSON.stringify(error))
              })
              this.showToast(item.title)
            })
            .alignRules({
              top: { anchor: "__container__", align: VerticalAlign.Top },
              left: { anchor: "__container__", align: HorizontalAlign.Start },
              // bottom: { anchor: "__container__", align: VerticalAlign.Bottom },
              // right: { anchor: "__container__", align: HorizontalAlign.End }
            })
            .id("image")

          Text(item.title)
            .width('100%')
            .padding(10)
            .fontColor(Color.White)
            .backgroundColor($r('app.color.transparent_backgroundColor'))
            .alignRules({
              bottom: { anchor: "image", align: VerticalAlign.Bottom },
              left: { anchor: "image", align: HorizontalAlign.Start }
            })
            .id("text")
        }
      }, (item: WanBannerBean) => JSON.stringify(item))
    }
    .borderRadius($r('app.float.home_swiper_borderRadius'))
    .width('100%')
    .height('25%')
    .autoPlay(true)
    .indicatorStyle({ mask: true, bottom: '10vp', right: '20vp', selectedColor: Color.Red })
    .margin({ top: '5vp', bottom: '10vp' })
  }

  @Builder ArticleListLayout() {
    // 可以进行页面下拉操作并显示刷新动效的容器组件
    // 1、refreshing  : boolean  必填参数 当前组件是否正在刷新。该参数支持$$双向绑定变量
    // 2、offset  : string | number 非必填参数 (下拉起点距离组件顶部的距离。默认值:16,单位vp,offset取值范围[0vp,64vp]。大于64vp按照64vp处理。不支持百分比,不支持负数)
    // 3、friction  number | string  非必填参数  下拉摩擦系数,取值范围为0到100。默认值:62
    // - 0表示下拉刷新容器不跟随手势下拉而下拉。
    // - 100表示下拉刷新容器紧紧跟随手势下拉而下拉。
    // - 数值越大,下拉刷新容器跟随手势下拉的反应越灵敏。
    Refresh({ refreshing: $$this.isRefreshing, offset: 120, friction: 100 }) {
      this.ArticleListComponent()
    }
    .onStateChange((refreshStatus: RefreshStatus) => {

    })
    .onRefreshing(() => {
      this.getWanArticleList();
    })
    // 注意:在List组件上添加了Text组件后,List组件无法拖动到底部
    // 解决方法:
    // 在List的父容器加上代码layoutWeight(1)。
    // 原理:List属于可滚动容器组件,默认高度是占满全屏幕高度,当出现其他固定高度的组件占领了屏幕的部分高度时,
    // 需要开发人员显性的指定List组件占满剩余高度,而不是全屏幕高度。.layoutWeight(1)
    // .layoutWeight(1)
    // 但是如果联动滚动的话,就不能添加.layoutWeight(1)

  }

  showToast(message: string) {
    prompt.showToast({
      message: message
    })
  }

  build() {
    Column(){
      if (this.pageState === PageState.Loading) {
        Column() {
          LoadingProgress().width('100vp').width('100vp').color(Color.Red);
        }
      } else if (this.pageState === PageState.Fail) {
        this.FailLayout(() => {
          this.pageState = PageState.Loading;
          this.getWanArticleList();
        })
      } else if (this.pageState === PageState.Success) {
        Stack() {
          Column() {
            // 注意:在List组件上添加了Text组件后,List组件无法拖动到底部
            // 解决方法:
            // 在List的父容器加上代码layoutWeight(1)。
            // 原理:List属于可滚动容器组件,默认高度是占满全屏幕高度,当出现其他固定高度的组件占领了屏幕的部分高度时,
            // 需要开发人员显性的指定List组件占满剩余高度,而不是全屏幕高度。.layoutWeight(1)
            this.ArticleListLayout()
          }
          .backgroundColor($r('app.color.page_background'))

          if (this.isShowFloatingButton) {
            this.ReloadPageButton()
            this.LoadFirstPageButton()
            this.LoadNextPageButton()
          }

          if (this.isRefreshing || this.isRefreshingFromButton) {
            LoadingProgress()
              .width(75)
              .height(75)
              .color(Color.Red)
          }
        }
      }
    }
    .scale({ x: this.scale1 })
    .opacity(this.opacity1)
  }

  @Builder FailLayout(onClick: () => void) {
    Column() {
      Image($r('app.media.ic_none'))
        .height(CommonConstants.NONE_IMAGE_SIZE)
        .width(CommonConstants.NONE_IMAGE_SIZE)
      Text($r('app.string.page_none_msg'))
        .opacity(CommonConstants.NONE_TEXT_opacity)
        .fontSize(CommonConstants.NONE_TEXT_size)
        .fontColor($r('app.color.fontColor_text3'))
        .margin({ top: CommonConstants.NONE_TEXT_margin })
    }
    .onClick(onClick)
  }
}

4、请求数据-WanArticleViewModel

import { ArticlePageListBean } from '../common/bean/ArticlePageListBean';
import ResponseBean from '../common/bean/ResponseBean';
import CommonConstants, { WanAndroidApiService } from '../common/constants/CommonConstants';
import { httpRequestByGet } from '../common/utils/HttpUtils';
import Logger from '../common/utils/Logger';
import { WanBannerBean } from '../common/bean/WanBannerBean';

class WanArticleViewModel {
  // 首页文章 https://www.wanandroid.com/article/list/0/json?page_size=2
  getWanArticleList(currentPage: number, pageSize: number, path: string): Promise<ArticlePageListBean> {
    return new Promise(async (resolve: Function, reject: Function) => {
      let url = `${WanAndroidApiService.WAN_ANDROID_SERVER}${path}${currentPage}`
      url += '/json' + '?page_size=' + pageSize;
      httpRequestByGet(url).then((data: ResponseBean) => {
        Logger.debug('接口请求地址: HomeArticleList:' + url);
        if (data.errorCode === CommonConstants.SERVER_CODE_SUCCESS) {
          Logger.debug('getWanArticleList success', JSON.stringify(data));
          resolve(data.data);
        } else {
          Logger.error('getWanArticleList failed', JSON.stringify(data));
          reject($r('app.string.page_none_msg'));
        }
      }).catch((error: Error) => {
        Logger.error('getWanArticleList failed', JSON.stringify(error));
        reject($r('app.string.http_error_message'))
      })
    })
  }

  // 首页Banner-GET-https://www.wanandroid.com/banner/json
  getWanHomeBanner(): Promise<WanBannerBean[]> {
    return new Promise(async (resolve: Function, reject: Function) => {
      let url = `${WanAndroidApiService.WAN_ANDROID_SERVER}${WanAndroidApiService.HOME_BANNER_LIST}`
      httpRequestByGet(url).then((data: ResponseBean) => {
        Logger.debug('接口请求地址: HomeBanner:' + url);
        if (data.errorCode === CommonConstants.SERVER_CODE_SUCCESS) {
          Logger.debug('getWanHomeBanner success', JSON.stringify(data));
          resolve(data.data);
        } else {
          Logger.error('getWanHomeBanner failed', JSON.stringify(data));
          reject($r('app.string.page_none_msg'));
        }
      }).catch((error: Error) => {
        Logger.error('getWanHomeBanner failed', JSON.stringify(error));
        reject($r('app.string.http_error_message'))
      })
    })
  }
}


let wanArticleViewModel = new WanArticleViewModel();

export default wanArticleViewModel as WanArticleViewModel;

5、简单封装网络请求框架工具

import ResponseBean from '../bean/ResponseBean';
import http from '@ohos.net.http';
import CommonConstants, { ContentType } from '../constants/CommonConstants';

/**
 * HTTP请求方法封装-GET
 */
export function httpRequestByGet(url: string): Promise<ResponseBean> {
  let httpRequest = http.createHttp();
  let responseResult = httpRequest.request(url, {
    method: http.RequestMethod.GET,
    readTimeout: CommonConstants.HTTP_READ_TIMEOUT,
    header: {
      'Content-Type': ContentType.JSON
    },
    connectTimeout: CommonConstants.HTTP_READ_TIMEOUT,
    extraData: {}
  });
  let serverData: ResponseBean = new ResponseBean();
  // 处理数据并返回
  return responseResult.then((value: http.HttpResponse) => {
    if (value.responseCode == CommonConstants.HTTP_CODE_200) {
      let result = `${value.result}`;
      let resultJson: ResponseBean = JSON.parse(result);
      if (resultJson.errorCode === CommonConstants.SERVER_CODE_SUCCESS) {
        serverData.data = resultJson.data;
      }
      serverData.errorCode = resultJson.errorCode;
      serverData.errorMsg = resultJson.errorMsg;
    } else {
      serverData.errorMsg = `${$r('app.string.http_error_message')}&${value.responseCode}`;
    }
    return serverData;
  }).catch(() => {
    serverData.errorMsg = $r('app.string.http_error_message');
    return serverData;
  })
}

网络请求这块很简单,没什么需要特别强调的地方,需要注意的点都在代码注释里标注了,大家可以看下代码。


总结

本节介绍了使用HarmonyOS-httpRequest进行HTTP网络请求获取数据处理我们的业务逻辑绘制UI,学会本章节,我们就可以利用手里的OpenApi设计我们自己的APP来对表Android、iOS以及跨平台技术开发的APP了,对比下实现效果、丝滑度以及我们实际开发中的真实感觉,相信你心中会有一个客观的打分。