首页 > 其他分享 >【最新鸿蒙应用开发】——优化之从启动和响应速度作为思路

【最新鸿蒙应用开发】——优化之从启动和响应速度作为思路

时间:2024-05-31 09:00:39浏览次数:13  
标签:鸿蒙 耗时 响应速度 item 使用 组件 思路 页面 加载

优化--提升应用启动速度和响应速度

从应用程序启动和运行过程的思路来思考,比如想办法提升冷启动速度,使用并行化(多线程并发,异步并发)、预加载、缓存等方法手段,提升系统资源利用率,减少主线程负载,加快应用的响应速度。以下是一些详细细节的总结。

1、提升应用冷启动速度

应用启动时延是影响用户体验的关键要素。当应用启动时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用, 这个启动方式就叫做冷启动。

应用冷启动过程大致可分成以下四个阶段:应用进程创建&初始化、Application&Ability初始化、Ability/AbilityStage生命周期、加载绘制首页,如下图:

1、减少import的模块

按需导入,尽可能使用系统提供的模块(第三方模块容易影响启动),来缩短应用程序的启动耗时;

2、设置合适分辨率的startWindowIcon

启动页图标分辨率过大,解码耗时会影响应用的启动速度;

3、避免AbilityStage生命周期回调接口进行耗时操作

应用启动流程中,系统会执行AbilityStage的生命周期回调函数,耗时操作建议通过异步任务延迟处理或者放到其他线程执行;

4、避免在Ability生命周期回调接口进行耗时操作

系统会执行Ability的生命周期回调函数,耗时操作建议通过异步任务延迟处理或者放到其他线程执行;

5、避免自定义组件生命周期回调接口中进行耗时操作

aboutToAppear函数会在创建自定义组件实例后,页面绘制之前执行,此时若在该函数中执行耗时操作,将阻塞UI渲染,增加UI主线程负担。在aboutToAppear()生命周期函数内建议只做当前组件的初始化逻辑,对于不需要等待结果的高耗时任务,可以使用多线程处理该任务,通过并发的方式避免主线程阻塞;也可以把耗时操作改为异步并发或延后处理,保证主线程优先处理组件绘制逻辑。

2、提升响应速度

1、开启多线程和使用异步并发

  • 使用多线程执行耗时操作

在日常开发过程中经常会碰到这样的问题:主页的开发场景中有多个Tab页展示不同内容,在首次加载完主页后,切换到第二个Tab页时需要加载和处理网络数据,导致第二个Tab页的页面显示较慢,有较大的完成时延。

碰到此类问题,我们可以在生命周期aboutToAppear中,使用多线程并发的方法执行第二个Tab页的网络数据访问解析、数据加载等耗时操作,既可以提前完成数据加载,也不会影响主线程UI绘制和渲染。

使用TaskPool进行耗时操作的示例代码如下:

import taskpool from '@ohos.taskpool';
​
aboutToAppear() {
  ...
  // 在生命周期中,使用TaskPool加载和解析网络数据
  this.requestByTaskPool();
}
​
@Concurrent
​
getInfoFromHttp(): string[] {
  // 从网络加载数据
  return http.request();
}
​
requestByTaskPool(): void {
  // 创建任务项
  let task: taskpool.Task = new taskpool.Task(this.getInfoFromHttp);
​
  try {
    // 执行网络加载函数
    taskpool.execute(task, taskpool.Priority.HIGH).then((res: string[]) => {
    });
  } catch (err) {
     logger.error(TAG, "failed, " + (err as BusinessError).toString());
  }
}

  • 使用异步执行耗时操作

问题:在aboutToAppear生命周期函数中,运行了业务数据解析和处理等耗时操作,影响了上一页面点击跳转该页面的响应时延。

可以把耗时操作的执行从同步执行改为异步或者延后执行,比如使用setTimeOut执行耗时操作,示例如下:

aboutToAppear() {
  ...
  // 在生命周期中,使用异步处理数据,延时大小视情况确定
  setTimeout(() => {
   this.workoutResult();
  }, 1000)
}
​
workoutResult(): string[] {
  // 处理需要展示的业务数据
  let data: Data[] = [];
  for(let i = 1; i < 100; i++) {
      result += data[i];
  }
  return result;
}

2、页面预加载

应该合理使用系统的预加载能力,例如Web组件的预连接、预加载、预渲染,使用List、Swiper、Grid、WaterFlow等组件的cachedCount属性实现预加载,使用条件渲染实现预加载)等,提升页面的启动和响应速度。

  • 使用Web组件的预连接、预加载、预渲染能力

当我们碰到Web页面加载慢的场景,我们可以使用Web组件的预连接、预加载、预渲染能力,在应用空闲时间提前进行Web引擎初始化和页面加载,提升下一页面的启动和响应速度。

示例代码如下:

import webview from '@ohos.web.webview';
​
preload() {
​
  // Web组件引擎初始化
  webview.WebviewController.initializeWebEngine();
​
  // 启动预连接,连接地址为即将打开的网址
  webview.WebviewController.prepareForPageLoad('https://gitee.com/harmonyos-cases/cases', true, 2);
​
}
...

  • 使用cachedCount属性实现预加载

推荐在使用List、Swiper、Grid、WaterFlow等组件时,配合使用cachedCount属性实现预加载。示例代码如下所示:

  private source: MyDataSource = new MyDataSource();
​
  build() {
    List() {
      LazyForEach(this.source, item => {
        ListItem() {
          Text("Hello" + item)
            .fontSize(50)
            .onAppear(() => {
              console.log("appear:" + item)
            })
        }
      })
    }.cachedCount(3) // 扩大数值appear日志范围会变大
  }

  • 使用条件渲染实现预加载

问题:页面布局复杂度较高,导致跳转该页面的响应时延较高。

可以使用条件渲染(详细介绍可参考文章:合理选择条件渲染和显隐控制的方式,添加页面的简单骨架图作为默认展示页面,等数据加载完成后再显示最终的复杂布局,加快点击响应速度。

示例代码如下:

import skeletonComponent from "./skeletonComponent"
import businessComponent from "./businessComponent"
​
@State isInitialized: boolean = false
​
build() {
  // 当数据未就位时展示骨架图,提升点击响应速度,减少页面渲染时间
  if(!this.isInitialized) {
    // 网络数据未获取前使用骨架图
    skeletonComponent();
  } else {
    // 数据获取后再刷新显示内容
    businessComponent();
  }
}

3、缓存

在列表场景中,我们推荐使用LazyForEach+组件复用+缓存列表项的能力,替代Scroll/ForEach实现滚动列表场景的实现,加快页面启动速度,提升滑动帧率;在一些属性动画的场景下,我们可以使用renderGroup缓存提升属性动画性能;也可以使用显隐控制对页面进行缓存,加快页面的显示响应速度。

  • 组件复用

HarmonyOS应用框架提供了组件复用能力,可复用组件从组件树上移除时,会进入到一个回收缓存区。后续创建新组件节点时,会复用缓存区中的节点,节约组件重新创建的时间。

若业务实现中存在以下场景,并成为UI线程的帧率瓶颈,推荐使用组件复用:

1、列表滚动(本例中的场景):当应用需要展示大量数据的列表,并且用户进行滚动操作时,频繁创建和销毁列表项的视图可能导致卡顿和性能问题。在这种情况下,使用列表组件的组件复用机制可以重用已经创建的列表项视图,提高滚动的流畅度。

2、动态布局更新:如果应用中的界面需要频繁地进行布局更新,例如根据用户的操作或数据变化动态改变视图结构和样式,重复创建和销毁视图可能导致频繁的布局计算,影响帧率。在这种情况下,使用组件复用可以避免不必要的视图创建和布局计算,提高性能。

3、地图渲染:在地图渲染这种场景下,频繁创建和销毁数据项的视图可能导致性能问题。使用组件复用可以重用已创建的视图,只更新数据的内容,减少视图的创建和销毁,能有效提高性能。

示例代码如下:

// xxx.ets
class MyDataSource implements IDataSource {
  private dataArray: string[] = [];
  private listener: DataChangeListener | undefined;
  ...
}
​
@Entry
@Component
struct MyComponent {
  private data: MyDataSource = new MyDataSource();
​
  aboutToAppear() {
    for (let i = 0; i < 1000; i++) {
      this.data.pushData(i.toString());
    }
  }
​
  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string) => {
        ListItem() {
          ReusableChildComponent({ item: item })
        }
      }, (item: string) => item)
    }
    .width('100%')
    .height('100%')
  }
}
​
@Reusable
@Component
struct ReusableChildComponent {
  @State item: string = ''
  // 复用时触发的生命周期
  aboutToReuse(params: ESObject) {
    this.item = params.item;
  }
​
  build() {
    Row() {
      Text(this.item)
        .fontSize(20)
        .margin({ left: 10 })
    }.margin({ left: 10, right: 10 })
  }
}

  • 使用renderGroup缓存提升属性动画性能

页面响应时,可能大量使用属性动画和转场动画,当复杂度达到一定程度之后,就有可能出现卡顿的情况。renderGroup是组件通用方法,它代表了渲染绘制的一个组合。

具体原理是在首次绘制组件时,若组件被标记为启用renderGroup状态,将对组件及其子组件进行离屏绘制,将绘制结果合并保存到缓存中。此后当需要重新绘制相同组件时,就会优先使用缓存而不必重新绘制了,从而降低绘制负载,进而加快响应速度。

示例代码如下:

// Index.ets

import { IconItem } from './IconItem'

// IconItem相关数据
class IconItemSource {
  image: string | Resource = ''
  text: string | Resource = ''
  ...
}

@Entry
@Component
struct Index {
  private iconItemSourceList: IconItemSource[] = [];

  aboutToAppear() {
    // 遍历添加IconItem的数据
    this.iconItemSourceList.push(
      new IconItemSource($r('app.media.img1'), `label1`),
      new IconItemSource($r('app.media.img2'), `label2`),
      new IconItemSource($r('app.media.img3'), `label3`),
    );
  }

  build() {
    Column() {
      // IconItem放置在grid内
      GridRow({}) {
        ForEach(this.iconItemSourceList, (item: IconItemSource) => {
          GridCol() {
            IconItem({ image: item.image, text: item.text })
              .transition(
                TransitionEffect.scale({})
                  .animation({})
                  .combine(TransitionEffect.rotate({})
                  .animation({ }))
              )
          }
        })
      }
    }
  }
}



// IconItem.ets
​
@Component
export struct IconItem {
  ...
  build()  {
    Flex()  {
      Image(this.image)
      Text(this.text)
    }
    // 在IconItem内开启renderGroup
    .renderGroup(true)
  }
}

  • 使用显隐控制进行页面缓存

控制元素显示与隐藏是一种常见的场景,使用Visibility.None、if条件判断等都能够实现该效果。其中if条件判断控制的是组件的创建、布局阶段,visibility属性控制的是元素在布局阶段是否参与布局渲染。使用时如果使用的方式不当,将引起性能上的问题。 如果会频繁响应显示与隐藏的交互效果,建议使用切换Visibility.None和Visibility.Visible来控制元素显示与隐藏,在组件无需展示的时候进行缓存,提高性能。

示例代码如下:

@State isVisible: boolean = true;
​
build() {
  Column() {
    Button("Switch visible and hidden").onClick(() => {
        this.isVisible = !(this.isVisible);
    })
    Stack() {
      Scroll() {
        Column() {
          Image($r('app.media.icon'))
        }
      }.visibility(this.isVisible ? Visibility.Visible : Visibility.None)// 使用显隐控制切换,不会频繁创建与销毁组件
    }  
  }  
}

标签:鸿蒙,耗时,响应速度,item,使用,组件,思路,页面,加载
From: https://blog.csdn.net/m0_68038853/article/details/139291443

相关文章

  • 鸿蒙HarmonyOS实战-Web组件(页面跳转和浏览记录)
    ......
  • TYUT移动框架技术(鸿蒙开发)复习提纲
    好多...一点一点写主要是整理一些上课说到的概念,大概看一下,只可能出选择填空简答什么的,老师发的那个认证题库最好也看一下,我感觉大概率会出那里的题。代码什么的可以看这个这个 ,我感觉还是挺不错的。考试前一周我会再出一个代码的。第一章HarmonyOS设计理念一次开发,......
  • 5.28应急响应思路流程
    1、恶意外联,ip封禁及溯源准备工作:对恶意ip信息收集,如fofa、钟馗之眼、资产绘测等等;受害者信息收集,如:开放端口,判断入侵点;2、现场调研互联网结构,数据流向,核心交互机(是否有服务器);日志审计:windows系统日志中,wife连接日志可以确认安全事件发生时间;是否有态势感知平台,判断外联时间......
  • 安卓再见!华为纯血鸿蒙截图流出,鸿蒙操作系统时代已经来临!6 月 21 日见!
    5 月 25 日上午,开放原子开源基金会 OpenHarmony 开发者大会 2024 于深圳正式举行,会上余承东表示,华为在2020年就将HarmonyOS的基础能力贡献给了开放原子开源基金会,截至目前,已有2000多名开发者支持OpenHarmony社区发展,累计贡献核心代码6200多万行。华为表示,Op......
  • 鸿蒙开发进入Harmony OS(闭源)新里程
    早在2020年,华为就开始推出自己的移动操作系统--OpenHarmony,这个被鸿蒙视为构建鸿蒙系统的基础或"地基"。经过接近4年的开发者生态拓展,OpenHarmony这个开源系统已有超过300家伙伴加入OpenHarmony生态共建、7500多名共建者参与贡献,贡献代码超过1.1亿行,累计有227个厂家的596款软硬......
  • 鸿蒙HarmonyOS实战-Web组件(前端函数和应用侧函数相互调用)
    ......
  • 用户信息维表设计思路
    用户信息维表设计思路原创语兴呀语数2024-05-2909:26江苏数据开发交流(联系管理员进群)图片多系统数据整合与优化在大数据时代,用户信息往往来源于多个不同的系统,例如淘宝天猫线上订单、抖店线上订单、自有APP和小程序、线下门店等。如何将这些不同来源的数据整合成一个统......
  • 【HarmonyOS Next】游戏对接鸿蒙系统
    一、开发环境要求Unityversions:需要更新到Unity2022LTS然后使用最新团结引擎:https://unity.cn/tuanjie/releasesDevEcoStudioBuildVersion:4.1.3.600及以上版本TargetAPI:11orlaterhvigor版本:4.1.1hvigor-ohos-plugin版本:4.1.1hvigor-ohos-arkui-x-......
  • 鸿蒙HarmonyOS实战-Web组件(基本使用和属性)
    ......
  • CCF-CSP真题《202403-1 词频统计》思路+python满分题解
    哇q(≧▽≦q),第一次写博客,请大家多多关照○| ̄|_ 看到没啥人提供202403的第一题解题思路及python代码,刚好写完,心血来潮想分享解题思路,就写下了这篇博客,有其他的编码版本,欢迎大家一起探讨呀(虽然我是算法菜鸟┗(T﹏T)┛,但有问题,我会尽力回答的!!!)好了废话不多说,上解题思路!大概想了......