前端卷的不行,岗位也少,花了一个星期把HarmonyOS应用开发者基础认证和HarmonyOS应用开发者高级认证拿下了,但是是纯应付考试,实际开发经验还不足,网上搜也搜不到鸿蒙的面试题,有也是用AI瞎吉儿写的,不得已面了几家整理了下面试题和自己找的答案,除了概念性内容不要硬背,理解为主。希望鸿蒙开发能救我一条狗命吧/(ㄒoㄒ)/~~有大佬内推的请悄咪咪的联系我哦。
现在的官网文档和特性更新很快很频繁,所以指不定啥时候就增加/删除一些东西了,有错误很正常,提醒我修改下。
1. Harmony OS App打包后的包名后缀是什么?
- 发布包:.hap
- 调试包:.hap.debug
- 预览包:.hap.preview
2. 页面和自定义组件生命周期有哪些?
2.1 页面(有@Entry装饰器的component)的生命周期:
- onPageShow:页面每次显示时触发一次,包括路由过程、应用进入前台等场景。
- onPageHide:页面每次隐藏时触发一次,包括路由过程、应用进入后台等场景。
- onBackPress:当用户点击返回按钮时触发。
2.2 自定义组件(由@Component装饰器修饰的component)的生命周期:
- aboutToAppear:组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。
- onDidBuild:API12新增,组件build()函数执行完成之后回调该接口,不建议在onDidBuild函数中更改状态变量、使用animateTo等功能,这会导致不稳定的UI表现。
- aboutToDisappear:aboutToDisappear函数在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改会导致应用程序行为不稳定。
3. 如何进行数据持久化?
- 用户首选项(Preferences):这是一种轻量级的配置数据持久化方式,适用于保存应用配置信息、用户偏好设置等。它通过文本形式保存数据,并且数据会全量加载到内存中,因此访问速度快,但不适合存储大量数据。
- 键值型数据库(KV-Store):适用于存储结构简单的数据,如商品名称和价格、员工工号和出勤状态等。键值型数据库以"键值对"的形式组织数据,适合数据关系不复杂的场景。
- 关系型数据库(RelationalStore):基于SQLite,适用于存储包含复杂关系的数据,如学生信息、雇员信息等。关系型数据库提供了一系列SQL操作,如增删改查等。
4. 如何进行全局状态管理?
- @State装饰器:用于组件内部的状态数据,当状态数据被修改时,会触发组件的build()方法刷新UI。
- @Prop装饰器:用于建立父子组件之间的单向数据绑定。
- @StorageLink装饰器:用于与AppStorage建立双向数据绑定,实现数据的全局共享和持久化。
- AppStorage:提供应用级别的状态管理,可以跨组件和页面共享状态数据。
- PersistentStorage:与AppStorage配合使用,实现数据的持久化存储。
- LocalStorage:页面级的UI状态存储,用于页面内或UIAbility内的状态共享。
- Environment:提供应用程序运行环境的参数,可以与AppStorage搭配使用。
5. LocalStorage在应用重启后数据会消失吗?
会,因为LocalStorage 是一种用于页面或组件级别的数据存储方式,它允许开发者在页面或组件的生命周期内存储和检索数据。LocalStorage 的数据存储在内存中,因此它的读写速度相对较快。但是,当应用重启后,LocalStorage 中的数据会丢失。
6. 父子组件如何通信?
@Prop装饰器、@Link装饰器、@Provide和@Consume装饰器、@Event装饰器、@Parame装饰器、@Provider装饰器和@Consumer装饰器
当前(API 12)状态管理有两个版本 V1 和 V2
- V1版本 :
- 父组件可以通过设置子组件的属性来传递数据。子组件通过定义
@Prop
装饰器和@Link
装饰器修饰的变量来接收从父组件传递过来的属性值。 @Provide
和@Consume
装饰器:本是用于跨组件通信,但父组件也可通过@Provide
装饰器提供数据,子组件通过@Consume
装饰器消费数据。
- 父组件可以通过设置子组件的属性来传递数据。子组件通过定义
- V2版本(开发中,不稳定)
@Param
装饰器:用于父组件向子组件传递数据,类似V1的@Prop
。- 子组件通过
@Event
装饰器装饰回调方法并调用,可以实现更改数据源的变量,再通过@Local
的同步机制,将修改同步回@Param
,以此达到主动更新@Param
装饰变量的效果。 - 使用
@Provider
装饰器和@Consumer
装饰器,类似V2的@Provide
和@Consume
装饰器,具体区别见 27
7. 兄弟组件如何通信?
- 通过公共父组件传递:
如果两个组件是同一个父组件的子组件,可以通过父组件来传递数据或事件。父组件可以作为中介,将一个子组件的数据或事件传递给另一个子组件。 - 使用全局状态管理:
使用全局状态管理(如 AppStorage)来存储共享数据。兄弟组件可以独立地读取和更新这个全局状态,从而实现通信。
8. 如何实现页面间的通信?
页面间通信可以通过路由的方式实现,路由可以实现页面间的跳转,也可以实现页面间的数据传递。
9. Navigation组件跳转和router跳转有什么区别?
-
Navigation
:是路由容器组件,适用于模块内和跨模块的路由切换,一次开发,多端部署场景。Router
位于页面栈管理节点stage
下面,不提供导航容器的概念。
-
Navigation
和Router
都支持跳转传参,但Router
对象中暂不支持方法变量。
-
Navigation
:支持清理指定路由,页面栈没有上限,可以无限跳转。Router
不支持清理指定路由且页面栈最大为32,页面栈到达32之后必须清除之后才能继续跳转。
-
Navigation
:支持自定义转场动画和共享元素转场动画。Router
:仅支持简单自定义转场动画。
-
Navigation
:支持通过setInterception
方法设置路由拦截。Router
:不支持路由拦截。
-
Navigation
:支持沉浸式页面和模态嵌套路由。Router
:不支持,需要通过窗口配置实现沉浸式页面。
总而言之,Navigation
组件在功能上更具丰富性和灵活性,特别是在处理复杂的导航结构、动效和路由管理方面。
而 Router
则提供了更基础的路由跳转功能,适合简单的路由需求。开发者可以根据应用的具体需求和设计选择最合适的路由方案。
完整的区别如下表:
业务场景 | Navigation | Router |
---|---|---|
一多能力 | 支持,Auto模式自适应单栏跟双栏显示 | 不支持 |
跳转指定页面 | pushPath & pushDestination | pushUrl & pushNameRoute |
跳转HSP中页面 | 支持 | 支持 |
跳转HAR中页面 | 支持 | 支持 |
跳转传参 | 支持 | 支持 |
获取指定页面参数 | 支持 | 不支持 |
传参类型 | 传参为对象形式 | 传参为对象形式,对象中暂不支持方法变量 |
跳转结果回调 | 支持 | 支持 |
跳转单例页面 | 支持 | 支持 |
页面返回 | 支持 | 支持 |
页面返回传参 | 支持 | 支持 |
返回指定路由 | 支持 | 支持 |
页面返回弹窗 | 支持,通过路由拦截实现 | showAlertBeforeBackPage |
路由替换 | replacePath & replacePathByName | replaceUrl & replaceNameRoute |
路由栈清理 | clear | clear |
清理指定路由 | removeByIndexes & removeByName | 不支持 |
转场动画 | 支持 | 支持 |
自定义转场动画 | 支持 | 支持,动画类型受限 |
屏蔽转场动画 | 支持全局和单次 | 支持 设置pageTransition方法duration为0 |
geometryTransition共享元素动画 | 支持(NavDestination之间共享) | 不支持 |
页面生命周期监听 | UIObserver.on('navDestinationUpdate') | UIObserver.on('routerPageUpdate') |
获取页面栈对象 | 支持 | 不支持 |
路由拦截 | 支持通过setInterception做路由拦截 | 不支持 |
路由栈信息查询 | 支持 | getState() & getLength() |
路由栈move操作 | moveToTop & moveIndexToTop | 不支持 |
沉浸式页面 | 支持 | 不支持,需通过window配置 |
设置页面标题栏(titlebar)和工具栏(toolbar) | 支持 | 不支持 |
模态嵌套路由 | 支持 | 不支持 |
10. HarmonyOS与Android和iOS有什么区别?
HarmonyOS 是华为开发的一个开源、分布式的操作系统。它设计用于多种设备,包括智能手机、平板电脑、智能电视和物联网设备。与Android和iOS的主要区别在于:
- 分布式架构:鸿蒙OS支持跨设备无缝协作,允许设备之间共享硬件资源。
- 性能:鸿蒙OS优化了任务调度和内存管理,提高了性能和响应速度。
- 安全性:鸿蒙OS采用了多层次的安全策略,包括数据加密和安全启动。
- 生态系统:鸿蒙OS正在构建自己的应用生态系统,鼓励开发者使用Ark Ts和ArkUI框架。
11. 什么是Ability?
在HarmonyOS中,Ability是应用的基本组成单元和入口,类似于Android中的Activity或iOS中的ViewController。Ability分为两种类型:
- FA(Feature Ability):提供独立功能的Ability,可以单独运行。
- PA(Particle Ability):轻量级的Ability,通常与FA一起出现,用于实现特定的用户界面或交互。
12. ArkUI框架有哪些特点?
ArkUI是鸿蒙OS的UI开发框架,其特点包括:
- 声明式UI:使用XML或ETS(Enlightenment Template Script)文件声明UI结构。
- 组件化:提供了丰富的组件,如按钮、列表、导航等,支持组件的复用和嵌套。
- 动态能力:支持动态加载和卸载UI组件,优化内存使用。
- 响应式布局:能够根据不同设备和屏幕尺寸自适应布局。
13. 如何在鸿蒙应用中实现跨设备通信?
鸿蒙OS支持多种跨设备通信方式,包括:
- 分布式软总线:一种高性能的通信机制,允许设备之间建立直接连接,进行数据传输。
- 蓝牙:使用标准的蓝牙技术进行设备间的通信。
- WLAN:通过WLAN网络实现设备间的通信。
- 远程服务调用:通过分布式任务调度实现跨设备的服务调用。
14. 如何实现应用的后台运行?
- 后台服务:使用后台服务(如BackgroundService)来执行不需要用户直接交互的任务。
- 定时任务:通过系统提供的定时任务机制(如AlarmService)来周期性执行后台任务。
- 事件监听:注册系统事件,如网络变化、电量变化等,以在特定事件发生时唤醒应用进行处理。
15. Ability是如何与用户交互的?
- 界面显示:Ability可以包含一个或多个AbilitySlice,用于显示UI界面并与用户进行交互。
- 事件处理:Ability可以处理用户的输入事件,如触摸、按键等。
- 数据绑定:Ability可以使用数据绑定机制,将UI组件与数据模型绑定,实现数据的自动更新和交互。
- 通知:Ability可以通过系统通知机制向用户发送通知,即使应用不在前台运行。
16. 如何实现应用的多语言支持?
- 资源文件:为每种语言创建资源文件(如string.json),并在里面定义所有可本地化的字符串。
- 资源引用:在代码中使用资源ID引用字符串,而不是硬编码文本。
- 系统设置:应用会自动根据系统设置的语言环境加载相应的资源文件。
- 动态切换:支持在应用运行时切换语言,并动态更新UI。
17. 分布式数据库是如何实现数据同步的?
- 分布式事务:确保跨设备的数据库操作具有原子性、一致性、隔离性和持久性。
- 数据版本控制:为数据添加版本号,确保同步时数据的一致性。
- 冲突解决策略:定义冲突解决策略,处理并发操作导致的数据冲突。
- 网络状态感知:根据网络状态智能同步数据,优化同步效率和流量使用。
18. 如何优化应用的性能?
- 内存管理:合理分配和释放内存,避免内存泄漏。
- 后台优化:合理使用后台服务和定时任务,避免不必要的后台运行。
- UI渲染优化:使用轻量级的UI组件,减少布局复杂度,优化渲染性能。
- 资源优化:压缩图片和媒体资源,减少应用的体积和加载时间。
19. HarmonyOS中的权限管理模型是怎样的?
- 权限声明:应用在config.json中声明所需的权限。
- 权限申请:在应用运行时,根据需要动态申请权限。
- 权限检查:在执行敏感操作前,检查是否已获得相应权限。
- 权限分组:系统将权限分为不同的组,便于管理和申请。
20. LazyForEach是什么?
LazyForEach 是一个用于高效渲染列表的组件或功能,它允许开发者在用户滚动列表时才加载和渲染列表项,而不是一次性渲染整个列表。这种按需渲染的方式可以显著提高应用的性能,特别是在处理大量数据时。
21. LazyForEach的工作原理是什么?
LazyForEach 的工作原理通常是基于用户的滚动位置来动态地创建和销毁列表项的组件实例。当用户滚动到列表的某个部分时,LazyForEach 会加载并渲染那些即将进入视图的列表项,同时可能会卸载那些滚出视图的列表项,以节省内存和计算资源。
22. Router.replace()方法的作用是什么?和Router.pushUrl()方法有什么区别?
Router.replace()方法用于替换当前路由,并将目标路由压入栈顶。与Router.pushUrl()方法不同,Router.replace()方法不会保留当前路由,而是直接替换掉当前路由。
23. 如何实现应用的沉浸式模式?
沉浸式模式是指应用界面呈现出沉浸式的全屏模式,不留任何系统UI,用户只能看到应用内容。在沉浸式模式下,应用的UI元素会被覆盖,但系统状态栏、导航栏、键盘等系统UI依然可见。以下是实现步骤
- 设置窗口属性:
在应用的入口Ability中,可以通过设置窗口属性来实现沉浸式模式。这通常涉及到配置窗口特性(Window Features)来隐藏状态栏和导航栏。 - 使用系统API:
鸿蒙OS提供了API来控制系统UI的显示和隐藏。你可以在应用的代码中调用这些API来实现沉浸式效果。 - 配置应用的配置文件:
在应用的config.json或其他配置文件中,可以声明应用需要的窗口特性,如ohos:immersive。 - 动态切换:
应用可以根据用户的交互或特定场景动态地进入或退出沉浸式模式。这可能涉及到监听用户的手势或其他事件来切换UI状态。 - 适配不同设备:
不同的设备可能有不同的屏幕和系统UI,因此在实现沉浸式模式时,需要考虑不同设备的适配问题。
24. 如何获取屏幕的安全区域?
- 可以通过设置组件的expandSafeArea属性来获取获取UIWindow:首先,你需要获取到当前页面的UIWindow实例。
- 调用getSafeArea方法:通过UIWindow实例调用getSafeArea方法来获取安全区域的Rect对象。
示例:
java
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.window.UIWindow;
import ohos.agp.utils.Rect;
public class MyAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
setUIContent(new SurfaceLayout(this));
UIWindow window = getUIWindow();
if (window != null) {
// 获取安全区域
Rect safeArea = window.getSafeArea();
// 在这里可以使用safeArea对象,它包含了安全区域的位置和尺寸信息
// 例如,可以使用safeArea.left, safeArea.top, safeArea.right, safeArea.bottom
}
}
}
25. ArkTs是什么?
ArkTS是HarmonyOS优选的主力应用开发语言。保持了TypeScript的基本风格,同时通过规范定义强化开发期静态检查和分析,提升程序执行稳定性和性能。
ArkTS的主要特点包括:
- 静态类型检查:ArkTS在编译时进行类型检查,这有助于在代码运行前发现和修复错误,提高代码的稳定性和性能。
- 声明式UI:ArkTS定义了声明式UI描述,允许开发者以更简洁、更自然的方式开发跨端应用。
- 状态管理:ArkTS提供了多维度的状态管理机制,使得与UI相关联的数据可以在组件内使用,也可以在不同组件层级间传递,支持单向和双向数据流。
- 渲染控制:ArkTS支持条件渲染、循环渲染和数据懒加载,允许开发者根据应用的不同状态渲染UI内容。
- 兼容性:ArkTS兼容TS/JavaScript生态,开发者可以使用TS/JS进行开发或复用已有代码。
- 并发机制:ArkTS支持轻量化的并发机制,允许开发者编写并发代码,提高应用的性能和响应速度。
26. ArkTs与TypeScript有什么区别?(答5点以上)
ArkTS 是基于 TypeScript 开发的框架,但是有一些限制和差异。ArkTS 旨在提供更严格的类型检查和优化的代码性能,同时确保与 HarmonyOS 的开发环境和特性兼容。以下是 ArkTS 与 TypeScript 的差异:
- 生成器函数 :ArkTS 不支持 TypeScript 中的生成器函数(使用
function*
定义的函数),应使用async
或await
机制进行并行任务处理 。 - 参数解构:在函数参数中使用解构赋值是 TypeScript 的特性,ArkTS 不支持参数解构,需要显式传递参数 。
- 函数内声明函数:TypeScript 允许在函数内部声明新的函数,而 ArkTS 不支持在函数内声明函数,应使用 lambda 函数代替 。
new.target
:ArkTS 不支持new.target
元属性,这是 TypeScript 中用于反射的属性 。- 确定赋值断言 :TypeScript 中的
!
确定赋值断言在 ArkTS 中不被支持,应初始化变量或使用其他方式确保赋值 。 - 原型上的赋值:ArkTS 不支持在对象的原型上进行赋值,这与 TypeScript 不同 。
globalThis
:ArkTS 不支持globalThis
,这是 TypeScript 中用于获取全局对象的属性 。Function.prototype.apply
、Function.prototype.call
和Function.prototype.bind
:ArkTS 不支持这些函数,它们在 TypeScript 中用于控制函数的this
绑定 。instanceof
和as
类型保护 :ArkTS 不支持is
运算符,必须使用instanceof
运算符替代,并且在使用之前,必须使用as
运算符将对象转换为需要的类型 。- 接口继承类:在 TypeScript 中,接口可以继承类,但在 ArkTS 中,接口只能继承接口 。
- 构造函数类型:ArkTS 不支持使用构造函数类型,应改用 lambda 函数 。
enum
声明合并 :ArkTS 不支持enum
声明合并,所有相关的枚举成员必须在同一个声明中 。- 命名空间作为对象:ArkTS 不支持将命名空间用作对象,可以使用类或模块替代 。
- 非声明语句在命名空间中:ArkTS 中,命名空间用于定义标志符可见范围,不支持命名空间中的非声明语句 。
import default as ...
:ArkTS 不支持import default as ...
语法,应使用显式的import ... from ...
语法 。require
和import
赋值表达式 :ArkTS 不支持通过require
导入,也不支持import
赋值表达式,应使用import
语法 。ambient
模块声明 :ArkTS 不支持declare module
语法,应直接导入需要的内容 。new.target
:ArkTS 不支持new.target
元属性,这是 TypeScript 中用于反射的属性 。Function.prototype.apply
、Function.prototype.call
和Function.prototype.bind
:ArkTS 不支持这些函数,它们在 TypeScript 中用于控制函数的this
绑定 。as const
断言 :ArkTS 不支持as const
断言,这是 TypeScript 中用于标注字面量的相应字面量类型的语法 。any
:ArkTS 不支持any类型, 应使用更具体的类型替代 。
27. @Provider和@Consumer vs @Provide和@Consume的区别?
能力 | V2 装饰器@Provider 和@Consumer | V1 装饰器@Provide 和@Consume |
---|---|---|
本地初始化 | 允许本地初始化,当找不到@Provider 的时候使用本地默认值。 | 禁止本地初始化,当找不到对应的@Provide 时候,会抛出异常。 |
支持类型 | 支持 function。 | 不支持 function。 |
观察能力 | 仅能观察自身赋值变化,如果要观察嵌套场景,配合@Trace 一起使用。 | 观察第一层变化,如果要观察嵌套场景,配合@Observed 和@ObjectLink 一起使用。 |
alias 和属性名 | alias 是唯一匹配的 key,如果缺省 alias,则默认属性名为 alias。 | alias 和属性名都为 key,优先匹配 alias,匹配不到可以匹配属性名。 |
从父组件初始化 | 禁止。 | 允许。 |
支持重载 | 默认开启,即@Provider 可以重名,@Consumer 向上查找最近的@Provider。 | 默认关闭,即在组件树上不允许有同名@Provide。如果需要重载,则需要配置 allowOverride。 |
28. @Prop和@ObjectLink装饰器有什么区别?
1.用途
@Prop
装饰器:主要用于在组件之间传递数据,将父组件的值传递给子组件。它定义了子组件的属性,可以接收来自父组件的赋值。@ObjectLink
用于建立对象之间的链接,通常用于在组件内部或组件之间共享和同步状态。它可以将一个对象的属性与另一个对象的属性进行链接,当一个对象的属性发生变化时,另一个对象的属性也会自动更新。
- 数据传递方式
@Prop
:是单向的数据传递,从父组件到子组件。父组件可以设置子组件的@Pro
p属性值,但子组件不能直接修改这个值。@ObjectLink
是双向的数据传递,父组件和子组件都可以修改子组件的@ObjectLink
属性值。
- 性能
@Prop
会深拷贝数据,具有拷贝的性能开销,性能低于@ObjectLink
详见官方文档。