一、基础概念(必问)

1. HarmonyOS 中 Stage模型 和 FA模型 的区别?为什么推荐Stage?

答案

  • FA(Feature Ability):早期模型,PageAbility承载页面,ServiceAbility服务能力,单HAP单进程,页面和能力耦合;能力启动、生命周期管理弱,后台管控差,不支持多HAP、元服务。
  • Stage模型:API9+主推模型,拆分 UIAbility(页面能力)+ ExtensionAbility(扩展能力);UIAbility代表应用实例,一个HAP可包含多个UIAbility;支持多HAP、原子化服务、独立Extension、精细化生命周期、更好的系统后台管控。
  • 推荐Stage:能力职责解耦、分布式/元服务必备、系统兼容性更好,官方后续不再迭代FA。

2. 什么是Ability?Ability有哪几种类型?各自作用?

答案
Ability是应用可对外提供的能力抽象,Stage下分两大类:

  1. UIAbility:带界面的能力,对应应用页面实例,可被拉起,拥有前后台生命周期。
  2. ExtensionAbility:无UI扩展能力,系统回调触发,常见:
    • ServiceExtensionAbility:后台服务
    • FormExtensionAbility:桌面卡片
    • WorkSchedulerExtensionAbility:定时任务
    • InputMethodExtensionAbility:输入法

3. AbilityStage的作用,什么时候会创建/销毁?

答案
AbilityStage是HAP模块的运行容器,一个HAP对应一个AbilityStage实例,同HAP内所有UIAbility共享同一个AbilityStage。

  • 创建:该HAP下第一个UIAbility启动时创建。
  • 销毁:该HAP内所有UIAbility全部销毁后,AbilityStage被系统回收。
    用途:存放模块全局资源、全局初始化、监听HAP级别事件。

4. 鸿蒙UI框架:ArkUI声明式与传统JSUI(类Web)的差异。

答案

  • JSUI:类Web的标签式开发,JS + HML + CSS,DOM式渲染,性能一般,仅FA模型支持,不再维护。
  • ArkUI(声明式):TS/ArkTS直接编写UI,无DOM,编译期生成原生渲染指令,渲染性能更高;天然适配Stage,支持状态驱动、组件复用、自定义装饰器。

5. 简述ArkTS是什么,和TS的区别,限制点有哪些?

答案
ArkTS是TypeScript的超集,为ArkUI定制,在TS基础上增加UI装饰器、状态管理语法;同时增加静态强类型约束。
区别&限制:

  1. 强制静态类型,不能隐式any;
  2. 提供@Component/@State等鸿蒙专属装饰器;
  3. 不支持部分JS动态特性:eval、动态new、动态属性增删;
  4. 编译阶段做类型校验,提前捕获错误。

6. 什么是元服务(原子化服务),和普通App区别?

答案
元服务(原子化服务):免安装、轻量HAP服务,用户无需安装应用即可直接使用功能,可从服务中心、卡片、二维码拉起。
区别:

  1. 无桌面图标;免安装,按需下发;
  2. 包体积限制更小;
  3. 能力以UIAbility/FormExtension对外提供;
  4. 不能后台常驻,生命周期由系统严格管控;普通App需要安装,有桌面图标。

7. 包结构:module、hap、app、bundle概念,HAP是什么?

答案

  • Module:工程内模块,分为entry模块(入口模块)、feature模块(业务模块);
  • HAP(Harmony Ability Package):编译后模块产物,一个module编译输出1个HAP;分为entry HAP(应用入口)、feature HAP(业务分包);
  • App:应用逻辑整体;
  • App Bundle:打包产物,由多个HAP组成,应用市场分发包。

8. 鸿蒙应用的安装包构成:HAP、app pack、hsap区别。

答案

  1. HAP:编译后的模块包,可独立调试安装;
  2. App Pack:发布包,包含多个HAP,应用市场分发原始包;
  3. HSAP:原子化服务包,轻量免安装包。

9. 应用沙箱是什么,沙箱目录有哪些?各自读写权限。

答案
沙箱:系统给每个应用分配独立隔离目录,应用只能访问自身沙箱,不能随意访问其他应用文件。
常用目录:

  • context.filesDir:持久私有文件,应用卸载删除,读写;
  • context.cacheDir:缓存目录,系统可自动清理;
  • context.tempDir:临时目录;
  • context.preferencesDir:Preferences存储目录;

媒体公共目录需要申请权限,不属于私有沙箱。

10. 权限分类:系统基础权限、敏感权限,动态申请流程。

答案

  • 基础权限:安装时自动授予,无需弹窗(网络等);
  • 敏感权限:涉及用户隐私,必须动态申请(相机、位置、存储)。
    动态申请流程:
  1. module.json5 声明权限;
  2. 代码调用accessToken.requestPermissions
  3. 监听授权结果回调;
  4. 判断是否授权,未授权做降级处理。

11. 简述HiLog,日志级别,开发/发布如何控制日志输出。

答案
HiLog:鸿蒙日志打印工具,替代console。
日志级别(从低到高):DEBUG、INFO、WARN、ERROR、FATAL。

  • DEBUG:仅调试使用,release包建议关闭;
  • 发布版本通过hilog过滤,关闭debug日志,避免泄露信息。
import hilog from '@ohos.hilog';
// 域id、标签、日志内容
hilog.info(0x0001, "TestTag", "页面加载:%s", "首页");
hilog.error(0x0001, "TestTag", "请求失败");

12. 应用生命周期(UIAbility):Create、Foreground、Background、Destroy,触发时机。

答案

  1. onCreate:UIAbility实例创建,仅一次,做初始化;
  2. onForeground:页面切前台,页面可见;
  3. onBackground:页面切后台,不可见;
  4. onDestroy:UIAbility销毁,释放资源。

二、ArkUI 核心(高频)

1. @Component、@Entry、@Builder、@BuilderParam 作用与区别。

答案

  • @Component:标记自定义组件;
  • @Entry:标记页面入口组件,挂载到UIAbility;
  • @Builder:组件内自定义UI构造函数,复用局部UI;
  • @BuilderParam:接收外部传入的@Builder函数,组件插槽能力。

示例代码:

// @Entry标记页面入口
@Entry
@Component
struct PageDemo {
  // @Builder 局部UI构造器
  @Builder TitleText(title:string) {
    Text(title).fontSize(20)
  }

  build() {
    Column() {
      this.TitleText("标题")
      // 传入builder到子组件
      ChildComponent({ titleBuilder: this.TitleText("子标题") })
    }
  }
}

@Component
struct ChildComponent {
  // 接收外部builder
  @BuilderParam titleBuilder: ()=>void
  build() {
    this.titleBuilder()
  }
}

2. 状态装饰器:@State / @Prop / @Link / @Watch / @ObjectLink / @Track,各自适用场景,单向/双向数据流。

答案

  • @State:组件内部状态,状态变更驱动UI刷新;本组件私有。
  • @Prop:父传子,单向只读,子不能直接修改;
  • @Link:父传子,双向绑定,父子同步;
  • @ObjectLink:复杂对象/数组双向绑定(引用类型);
  • @Watch:监听状态变化,触发回调;
  • @Track:只监听对象指定属性,细粒度更新,减少无效渲染。

示例:@State + @Link

@Entry
@Component
struct Parent {
  @State count: number = 0;
  build() {
    Column() {
      Text(`父组件count:${this.count}`)
      // @Link双向绑定,子修改同步父
      Child({childCount: $count})
    }
  }
}

@Component
struct Child {
  @Link childCount: number
  build() {
    Button("+1").onClick(()=>{
      this.childCount++
    })
  }
}

3. ArkUI渲染原理:什么是虚拟DOM?ArkUI是否使用虚拟DOM?渲染更新机制。

答案
ArkUI没有虚拟DOM
原理:声明式UI编译后生成渲染节点(RenderNode),状态变更时,框架对比状态,只更新变化节点,增量渲染。
虚拟DOM是React的方案,JS计算diff;ArkUI在编译期做优化,渲染链路更短。

4. ForEach 和 LazyForEach 区别,使用注意事项,性能坑。

答案

  • ForEach:一次性渲染全部列表项,大数据列表会一次性创建所有组件,卡顿、内存高;适合少量数据。
  • LazyForEach:懒加载,只渲染视口内可见条目,滑动复用,长列表必用。
    注意点:必须实现数据源IDataSource,key必须稳定唯一;key重复会渲染错乱。

示例 LazyForEach

class MyDataSource implements IDataSource {
  private list: string[] = []
  constructor(arr:string[]){
    this.list = arr
  }
  totalCount(): number {
    return this.list.length
  }
  getData(index: number): string {
    return this.list[index]
  }
  registerDataChangeListener(listener: DataChangeListener): void {}
  unregisterDataChangeListener():void {}
}

@Entry
@Component
struct ListDemo {
  data: MyDataSource = new MyDataSource(["A","B","C","D"])
  build() {
    List() {
      LazyForEach(this.data, (item:string)=>{
        ListItem(){Text(item)}
      }, (item:string)=>item) // key生成器,保证唯一
    }
  }
}

5. 自定义组件生命周期:aboutToAppear、aboutToDisappear触发时机。

答案

  • aboutToAppear:组件实例创建完成,build执行之前触发;适合初始化请求、赋值。
  • aboutToDisappear:组件销毁前触发,用来释放定时器、监听、订阅,防止内存泄漏。
@Component
struct Demo{
  aboutToAppear(){
    console.info("组件即将出现")
  }
  aboutToDisappear(){
    console.info("组件即将销毁,清理资源")
  }
  build(){Text("demo")}
}

6. NavDestination + NavRouter 路由框架,页面栈管理,和老Router的差异。

答案

  • NavRouter:路由容器;NavDestination:路由页面节点;维护页面栈,原生支持返回、页面参数、栈操作。
  • 老Router:API8及之前,Router.push,无统一页面栈管理,参数传递能力弱,官方推荐迁移NavDestination。

7. NavDestination 页面传参有哪几种方式,页面栈如何清除、拦截返回。

答案
传参方式:

  1. NavRouteInfo携带params参数;
  2. AppStorage全局状态;
    页面栈操作:pop()出栈,clear()清空栈;onBackPress拦截返回事件。

示例:页面跳转传参

@Entry
@Component
struct NavRootPage {
  @State pathStack: NavPathStack = new NavPathStack()
  build() {
    NavRouter(this.pathStack) {
      NavDestination() {
        Button("跳转详情页").onClick(()=>{
          // 跳转并传参
          this.pathStack.pushPath({name:"Detail",param:{id:100,name:"测试"}})
        })
      }.name("Home")
      NavDestination() {
        DetailPage()
      }.name("Detail")
    }
  }
}

@Component
struct DetailPage {
  @State params:any = null
  onReady(context: NavDestinationContext) {
    this.params = context.pathInfo.param
    hilog.info(0x001, "nav", `接收参数:${JSON.stringify(this.params)}`)
  }
  build() {
    Column(){Text(`id:${this.params?.id}`)}
  }
}

8. 组件复用:reuse,复用组件的生命周期。

答案
reuse开启组件复用,组件从缓存池中取出,不销毁重建;
生命周期:aboutToReuse(复用时触发),aboutToRecycle(回收缓存),不会走aboutToDisappear。适合长列表组件复用。

9. 布局原理:Flex、Column、Row、Stack,约束优先级(measure/layout流程)

答案

  1. Measure阶段:父给子宽高约束,子测量自身需要尺寸;
  2. Layout阶段:父确定子位置。
  • Row:水平线性布局;Column:垂直线性布局;Flex弹性;Stack堆叠(z轴)。
    约束优先级:组件width/height > layoutWeight > 内容自适应。

10. 动画:属性动画、显式动画、转场动画,animateTo使用注意点。

答案

  • 属性动画:组件属性animation,自动动画;
  • animateTo:显式动画,代码触发状态变更产生动画;
  • 页面转场:页面切换动画。
    注意:animateTo内部修改@State变量;动画只能驱动可动画属性。
@Entry
@Component
struct AnimDemo {
  @State w:number = 100
  build() {
    Column(){
      Button("动画")
        .onClick(()=>{
          animateTo({duration:500},()=>{
            this.w = 200
          })
        })
      Rect().width(this.w).height(100).fill(Color.Red)
    }
  }
}

11. 弹窗:AlertDialog、CustomDialog,自定义Dialog踩坑点。

答案
AlertDialog系统预置弹窗;CustomDialog自定义弹窗。
踩坑:弹窗不会跟随页面自动销毁;页面销毁必须关闭dialog,否则内存泄漏;弹窗层级问题。

@CustomDialog
struct MyDialog {
  controller: CustomDialogController
  build() {
    Column(){
      Text("自定义弹窗")
      Button("关闭").onClick(()=>this.controller.close())
    }
  }
}

@Entry
@Component
struct DialogPage {
  dialogCtrl: CustomDialogController = new CustomDialogController({builder:MyDialog()})
  build() {
    Button("打开弹窗").onClick(()=>this.dialogCtrl.open())
  }
}

12. 事件分发:触摸事件冒泡、阻止冒泡方式。

答案
触摸事件默认冒泡,子触发后向上传递父组件;使用stopPropagation()停止冒泡。

Column()
  .onTouch((e)=>{
    console.info("父")
  })
{
  Text("点击").onTouch((e)=>{
    console.info("子")
    e.stopPropagation() //阻止冒泡,父不会收到事件
  })
}

13. Canvas组件使用场景,离屏渲染怎么实现。

答案
Canvas用于自定义绘制(图表、签名);离屏渲染OffscreenCanvas,不绑定屏幕,后台绘制,提升性能。

三、Stage模型 & UIAbility(重中之重)

1. UIAbility的启动模式(单实例、多实例),怎么配置。

答案

  • singleton(单实例,默认):系统只存在一个UIAbility实例,多次拉起复用;
  • multiInstance(多实例):每次拉起新建实例,多个页面独立。
    配置在module.json5 -> abilities -> launchType。

2. UIAbility之间跳转,传参方式,跨Ability数据传递限制。

答案
使用Want跳转;参数放在want.parameters。
限制:只能传递基础类型,不能传大对象、句柄;大数据建议持久化后传递key。

3. UIAbility前后台切换会触发哪些生命周期,后台切前台数据丢失怎么处理。

答案
切后台onBackground;切前台onForeground。
后台被系统回收时实例销毁;解决方案:onSaveState保存数据到Preferences/RDB,onCreate读取恢复。

4. AbilityStage和UIAbility关系,同一个应用多个UIAbility是否共用一个AbilityStage?

答案
同HAP下所有UIAbility共享同一个AbilityStage;不同HAP有独立AbilityStage。

5. 启动参数want对象详解,want的action、uri、parameters。

答案
Want是跨能力拉起载体:
action:动作标识;uri:资源地址;parameters:参数键值对。

6. 应用冷启动、热启动的定义,冷启动流程。

答案
冷启动:进程不存在,系统新建进程,加载HAP、初始化AbilityStage、UIAbility、渲染页面;速度慢。
热启动:进程存活,UIAbility切后台,重新onForeground,不需要重建进程。

7. 应用退出方式:finish() 和 system.exit(0) 的区别,推荐用哪个。

答案

  • finish():关闭当前UIAbility,由系统管理生命周期,推荐;
  • system.exit(0):直接杀死进程,强制退出,跳过生命周期,资源无法释放,不推荐

8. 什么是ExtensionAbility?列举常用ExtensionAbility类型。

答案
无UI扩展能力,系统回调驱动;ServiceExtensionAbility、FormExtensionAbility卡片、WorkSchedulerExtensionAbility定时任务。

9. 后台限制:鸿蒙应用后台能力,后台任务怎么申请(延时任务、传输任务)

答案
系统严格限制后台常驻;长时间任务要申请后台任务(延时任务、网络传输任务),需要权限,超时系统会终止。

10. 进程模型:一个HAP可以有几个进程?多Ability是否在同一进程。

答案
一个HAP默认单进程;同HAP内所有UIAbility在同一个进程;可配置多进程(极少场景)。

四、数据持久化

1. Preferences 特点、适用场景,局限性。

答案
轻量键值存储,类似SharedPreferences;适合简单配置、开关;
局限:不适合大量数据、复杂查询、大对象;全量加载进内存。

import preferences from '@ohos.data.preferences';
async function prefsDemo(ctx:UIAbilityContext){
  let prefs = await preferences.getPreferences(ctx,"my_store")
  await prefs.put("name","zhangsan")
  await prefs.flush() //落盘
  let val = await prefs.get("name","")
}

2. RDB关系型数据库,使用步骤,RDB的增删改查,事务。

答案
RDB是sqlite封装,适合大量结构化数据,支持sql、事务。
步骤:1.获取RdbStore;2.建表;3.增删改查;4.关闭ResultSet。

import relationalStore from '@ohos.data.relationalStore';

async function rdbDemo(ctx:UIAbilityContext) {
  const config:relationalStore.RdbStoreConfig = {
    name:"test.db",
    securityLevel:relationalStore.SecurityLevel.S1
  }
  // 创建数据库
  let store = await relationalStore.getRdbStore(config,1)
  //建表
  await store.executeSql(`CREATE TABLE IF NOT EXISTS user(id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT)`)
  //插入
  await store.insert("user",{name:"张三"})
  //查询
  let resultSet = await store.query("user",["id","name"])
  while(resultSet.goToNextRow()){
    console.info(resultSet.getString(1))
  }
  resultSet.close() //必须关闭,防止内存泄漏
}

3. RDB 游标ResultSet使用注意点,内存泄漏场景。

答案
ResultSet用完必须close();忘记关闭游标会造成数据库句柄泄漏。

4. 三种持久化方案对比:Preferences / RDB / 文件读写。

答案

  • Preferences:轻量K-V,小配置;
  • RDB:结构化大量数据,支持SQL;
  • 文件读写:二进制/文本大文件,图片、文档。

5. 应用沙箱文件目录,如何获取沙箱路径,能否直接写绝对路径。

答案
通过context获取filesDir/cacheDir;禁止硬编码绝对路径,不同设备路径不同。

6. 跨HAP之间数据共享怎么做。

答案

  1. 统一RDB放在entry模块;
  2. 使用公共HSP封装数据库能力;
  3. 分布式数据管理。

7. 大文件存储方案,图片缓存放在哪个目录。

答案
图片缓存放cacheDir,系统可自动清理;大文件二进制使用fs读写。

五、工程构建 hvigor & 工程配置

1. hvigor是什么,hvigor和hvigor-ohos-plugin作用。

答案
hvigor是鸿蒙构建工具,替代旧的gradle;hvigor-ohos-plugin是鸿蒙构建插件,负责编译ArkTS、打包HAP。

2. module.json5 核心字段含义。

答案
模块配置文件:模块名称、abilities、权限、页面入口、元服务配置。

3. build-profile.json5 作用,编译选项配置。

答案
工程构建配置:签名、编译参数、产品配置、target。

4. HAP打包,debug/release包差异。

答案
debug:调试符号、日志、预览支持;release:代码压缩、去除调试信息,签名发布包。

5. 模块依赖:本地模块、HAR、HSP的区别。

答案

  • HAR:静态共享包,编译时代码拷贝到依赖方;版本固化;适合公共组件。
  • HSP:动态共享包,运行时加载,多HAP复用同一份代码;适合大公共业务模块。

6. HAR 和 HSP:静态共享包 vs 动态共享包,适用场景,版本依赖。

答案
HAR:静态,打包复制代码,简单组件库;HSP动态,运行时共享,减小包体积,多HAP项目。

7. 编译时报错:预览器白屏,排查思路。

答案

  1. 代码语法错误;
  2. @Entry页面缺失;
  3. 状态初始化异常;
  4. 资源路径错误;
  5. 版本/API不匹配。

8. 资源限定符(color、string、media)资源匹配规则。

答案
资源目录加限定词(zh_CN、dark),系统按设备语言、深浅色、分辨率自动匹配资源。

9. 多语言适配怎么实现。

答案
新建不同语言string.json资源,$r(“app.string.xxx”)引用,系统自动跟随设备语言。

10. 版本管理、签名配置,调试签名/发布签名。

答案
调试签名:DevEco自动生成,仅本机调试;发布签名:应用市场需要正式证书,打包AppPack。

六、性能优化(面试必问)

1. 鸿蒙应用卡顿排查思路,HiProfiler工具使用。

答案
HiProfiler性能分析工具,查看FPS、CPU、内存。排查步骤:

  1. 看FPS是否低于60;
  2. 定位主线程耗时函数;
  3. 查看UI渲染耗时;
  4. 定位频繁状态刷新、长列表、大图片。

2. UI渲染卡顿常见原因,如何定位。

答案
主线程阻塞(大量同步计算)、@State频繁更新、ForEach渲染大量节点、大图解码。
定位:HiProfiler、HiLog打点。

3. LazyForEach优化列表,避免列表卡顿的手段。

答案
使用LazyForEach代替ForEach;固定item高度;图片异步加载;减少item内部@State。

4. @State滥用带来的性能问题,状态最小化原则。

答案
@State变更会触发组件重建;不必要变量不要加@State;状态范围尽量缩小,只绑定需要刷新UI的数据。

5. 内存泄漏常见场景:定时器、事件监听、RDB游标、自定义组件。

答案

  1. setInterval定时器在aboutToDisappear未清除;
  2. 事件订阅没有取消监听;
  3. ResultSet游标忘记close;
  4. 全局持有组件实例引用,组件无法回收。

6. 图片优化:图片格式、尺寸、异步加载、缓存。

答案
使用webp减小体积;图片尺寸适配控件大小;使用AsyncImage;缓存放cacheDir。

7. 包体积优化方案。

答案
图片压缩、资源裁剪、HAR抽公共代码、移除无用资源、混淆、分包feature HAP。

8. 冷启动慢如何排查和优化。

答案
排查:HiProfiler看启动链路耗时;
优化:onCreate减少同步任务,延迟非必要初始化,懒加载页面资源。

9. 后台耗电优化,频繁唤醒问题。

答案
减少定时器轮询;优先系统回调任务;非实时逻辑批量处理。

10. 如何监测页面FPS。

答案
HiProfiler;开发者选项开启FPS悬浮窗。

七、分布式能力(中高级)

1. 分布式软总线是什么。

答案
跨设备通信底座,自动发现设备、组网,屏蔽不同设备通信差异。

2. 分布式数据管理(DistributedData)适用场景。

答案
多设备之间数据同步,同一账号下多端数据自动同步。

3. 分布式设备发现,跨设备拉起应用。

答案
通过软总线发现在线设备,使用Want指定deviceId拉起远端UIAbility。

4. 跨设备迁移:UIAbility迁移,迁移的限制。

答案
将当前页面迁移到另一设备;限制:两端应用版本一致,支持迁移权限,网络良好。

备注:普通应用岗问的浅,架构/分布式岗位深挖。

八、进阶架构 & 工程实践

1. 鸿蒙应用分层架构设计(推荐:UI层、业务层、数据层)

答案
三层架构:

  • UI层:ArkUI页面、组件,只负责展示,不写业务;
  • 业务层(ViewModel/Service):业务逻辑,状态转换;
  • 数据层:数据库、网络请求、本地存储。
    依赖方向:UI依赖业务层;业务层依赖数据层;单向依赖。

2. 如何在ArkTS实现MVVM,数据和UI解耦。

答案
ViewModel使用LocalStorage/AppStorage存放状态;UI监听状态,业务逻辑放在ViewModel,UI不处理业务。

3. 全局状态管理方案:AppStorage、LocalStorage,适用场景。

答案

  • LocalStorage:页面/组件树内局部全局;
  • AppStorage:整个应用全局状态。

4. AppStorage和LocalStorage区别,全局状态踩坑。

答案
AppStorage全局,生命周期跟随应用;LocalStorage绑定页面节点树;
踩坑:AppStorage大量数据不及时清理,内存持续占用。

5. 模块化拆分:业务模块抽HAR/HSP的边界怎么划分。

答案
通用基础组件、工具类抽HAR;大型公共业务模块,多HAP共享,抽HSP。业务模块按业务域拆分feature HAP。

6. 组件库封装思路,公共组件设计原则。

答案
单一职责;参数化配置;@BuilderParam插槽;对外最小暴露属性;事件回调解耦。

7. 埋点设计,HiLog封装。

答案
封装统一埋点服务,区分开发日志和业务埋点;生产环境关闭debug日志。

8. 异常捕获:全局异常捕获,JS崩溃捕获。

答案
UIAbility中注册应用全局错误监听,捕获JS异常,上报埋点。

9. 单元测试:hvigor单元测试,ArkUI组件测试。

答案
hvigor支持测试框架,对service、工具类写单元测试;组件测试使用ArkUI测试框架。

10. 灰度发布、应用市场上架流程。

答案
应用市场上传AppPack;配置灰度,分批次放量;审核后正式发布。

九、手写代码题(现场编码)

上面章节已经附带基础示例,这里汇总完整可运行代码片段

十、场景综合问答题(开放式,架构岗重点)

1. 用户反馈页面切换卡顿,你的排查步骤?

答案

  1. 复现问题,HiProfiler抓性能数据;
  2. 看主线程CPU,是否有大量同步计算;
  3. 查看页面节点数量,是否滥用ForEach;
  4. 检查@State范围,是否频繁刷新大量组件;
  5. 图片是否大图未压缩;
  6. 定位到代码后优化,替换LazyForEach、异步加载。

2. 项目越来越大,模块耦合严重,怎么重构?

答案

  1. 分层,UI/业务/数据解耦;
  2. 公共能力抽HAR/HSP;
  3. 消除跨模块直接import,使用接口;
  4. 按业务拆feature HAP;
  5. 全局状态收敛,减少跨页面直接依赖。

3. 应用后台被系统杀掉,如何保存现场,恢复页面状态?

答案
UIAbility的onSaveState,将页面状态存入RDB/Preferences;onCreate读取保存的状态,恢复页面数据。

4. 多HAP项目,公共业务如何复用,HAR还是HSP?

答案
基础组件、工具类:HAR;大业务模块,多个HAP同时引用,需要减少包体积:HSP。

5. 页面大量图片列表,滑动出现闪烁、内存飙升怎么处理?

答案

  1. LazyForEach;
  2. AsyncImage异步加载,设置合适宽高;
  3. 图片压缩;
  4. 图片缓存;
  5. 页面销毁释放图片资源。

6. 预览器白屏,从哪些方向排查?

答案

  1. @Entry页面语法报错;
  2. 导入模块不存在;
  3. 变量初始化异常,渲染时报错;
  4. API版本不匹配;
  5. 资源引用路径错误。

7. 敏感权限动态申请完整流程,如果用户拒绝权限怎么降级。

答案

  1. module.json5声明权限;
  2. 代码调用requestPermissions;
  3. 获取授权结果;
  4. 拒绝时,禁用相关功能,友好提示,引导用户去设置页手动开启权限。

8. 原子化服务开发和普通应用差异,需要注意什么。

答案
免安装,包大小限制严格;无桌面图标;生命周期由系统严格管控,不能后台长时间运行;元服务入口配置,支持卡片拉起。

十一、反问面试官(面试结尾用)

  1. 团队使用API哪个版本,Stage模型全面落地了吗?
  2. 项目是原生ArkTS还是跨端(uni-app等)?
  3. 项目组件库是自研还是官方组件扩展?
  4. 是否有分布式/原子化服务相关业务?

精简版|10道高频突击题(面试前速刷,带简答)

  1. Stage和FA区别
    答:FA老模型;Stage拆分UIAbility/ExtensionAbility,支持多HAP、元服务,推荐使用。
  2. 状态装饰器@State/@Link/@Prop/@ObjectLink区别
    答:@State内部状态;@Prop单向子只读;@Link双向简单类型;@ObjectLink复杂对象双向绑定。
  3. NavDestination路由使用和页面栈
    答:NavRouter容器,NavDestination页面;NavPathStack管理页面栈,push/pop。
  4. LazyForEach和ForEach区别
    答:ForEach一次性渲染全部;LazyForEach视口懒加载,长列表用。
  5. HAR和HSP
    答:HAR静态包,编译拷贝;HSP动态共享包,运行时复用。
  6. RDB和Preferences对比
    答:Preferences轻量K-V;RDB数据库,适合大量结构化数据,支持SQL事务。
  7. UIAbility生命周期,前后台切换
    答:onCreate创建;onForeground前台;onBackground后台;onDestroy销毁。
  8. 应用冷启动优化手段
    答:主线程减少同步任务,延迟初始化,懒加载资源。
  9. 内存泄漏常见场景
    答:定时器未清理、事件监听未取消、RDB游标不close、全局持有组件引用。
  10. AppStorage和LocalStorage
    答:AppStorage应用全局;LocalStorage组件树局部状态。

我可以再帮你拆分2种版本:

  1. 【纯题目版】(用于面试考官)
  2. 【题库+答案分离版】题目一页,参考答案单独一页(适合笔试自测)

你想要拆分吗?或者我再补充一套鸿蒙架构主观大题

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐