鸿蒙面试浪潮来袭,你是否也想着利用这次机会去实现,跳槽涨薪的梦呢?
如果关注了华为鸿蒙的人应该知道:鸿蒙开发岗位需求飙升6倍! 可想而知该岗位前景多么广阔,为此就为大家整理些(鸿蒙HarmonyOS)开发岗位面试题。
面试题目
以下问题是在面试过程中实际遇到的
1. 页面和组件的生命周期,及其流程
2. @Entry 装饰的页面和 Navigation 组件里的页面,有什么区别
- @Entry 装饰的页面
- 定义:是一个基本的页面,每一个页面都需要在 main_page.json 中声明
- 路由:这种页面是路由的起点,通常用于展示应用的入口
- 生命周期:具有通用的生命周期方法,如 @Entry 修饰的页面中的通用方法
- Navigation 组件
- 定义:是一个导航容器,挂载在单个页面下
- 路由:支持跨模块的动态路由,通过自定义路由表或系统路由表实现页面的跳转
- 页面结构:由标题栏、内容区和工具栏组成,支持页面的路由能力和多种显示模式
- 显示模式:可以设置为单页显示或分栏显示模式,适应不同设备尺寸
3. 常用的状态装饰器有哪些
分类 内容 管理组件拥有的状态 @State装饰器 组件内状态 @Prop装饰器 父子单向同步 @Link装饰器 父子双向同步 @Provide装饰器和@Consume装饰器 与后代组件双向同步 @Observed装饰器和@ObjectLink装饰器 嵌套类对象属性性变化 一般回答上面这几个就够了 管理应用拥有的状态 LocalStorage 页面级UI状态存储 AppStorage 应用全局的UI状态存储 PersistentStorage 持久化存储UI状态 其他状态管理 @Watch装饰器 状态变量更改通知 $$语法 内置组件双向同步 @Track装饰器 class对象属性级更新
4. 常用的动画有哪些
- 一、组件的属性动画
- 二、页面间的转场动画
- 三、lolita 库加载动画资源文件
5. ArkTs 和 Ts 有什么区别
ArkTs 基于 Ts 做了扩展,并且强化了静态检查和分析
- 一、扩展了 UI:
- 定义了声明式 UI 描述、自定义组件,事件方法、属性方法
- 提供了多维度的状态管理机制
- 提供了控制渲染、循环渲染的能力
- 二、强化了检查
- 不支持 var、any、unknown、Symbol
- 不支持解构赋值
- 不支持使用对象字面量进行类型声明
- 不支持在运行时动态增删对象的属性
- 不支持在函数内声明函数
- 不支持使用 typeof 作为类型
- 不支持使用 # 符号开头声明的私有字段,改用 private 关键字
- 不支持把 function 定义函数赋值给变量,改为使用箭头函数
6. 动态 import 加载模块,以及反射
// Calc.ets
export class Calc { public constructor() {} public static staticAdd(a: number, b: number): number { return a + b; } public instanceAdd(a: number, b: number): number { return a + b; }
} export function addHarLibrary(a: number, b: number): number { return a + b;
} // index.ets
let harLibrary = 'harlibrary'// 动态import变量是新增特性,入参换成字符串'harlibrary'是现有特性。也可使用await import方式
import(harLibrary).then((ns: ESObject) => { // 反射调用静态成员函数staticAdd() ns.Calc.staticAdd(7, 8); // 实例化类Calc let calc: ESObject = new ns.Calc(); // 调用实例成员函数instanceAdd() calc.instanceAdd(8, 9); // 调用全局方法addHarLibrary() ns.addHarLibrary(6, 7);
})
7. 如何做沉浸式状态栏
暂略,后续补充
8. 如何实现垂直的三栏布局
即:顶部显示标题,底部显示按钮,中间没有内容,但需要占满剩余空间
- 以下三种方式都行:
- Blank 组件
- Column 组件 + layoutWeight()
- Flex 组件
9. @Entry 装饰的页面,A 页面跳到 B 页面后再跳回 A 页面,如何获取 B 页面的返回值
router.back({url: 'pages/Home',params: {info: '来自Home页'} })// 这些参数可以在目标页面中 // 通过调用 router.getParams() 方法进行获取onPageShow() {const params = router.getParams() as Record<string, string>console.log(params)}
10. 如何实现给父组件传递子组件
- 使用 @BuilderParam
- 以下示例代码是我个人开发中该组件的简化版
@Component export struct Visible {@Prop isShow: boolean = true@BuilderParam children: () => void = this.EmptyBuilder@BuilderEmptyBuilder() {}build() {Column() {this.children()}.visibility(this.isShow ? Visibility.Visible : Visibility.Hidden)} }// 使用 Visible({ isShow: true }) {Tech() }
可能的面试题目
以下问题是我个人感觉可能被问到的
1. 使用router.back() 方法返回到原来的页面,会触发原页面的 aboutToAppear() 生命周期回调吗,会触发哪个生命周期?
不会触发 aboutToAppear,但是会触发 onPageShow()
2. UIAbility 和 WindowStage 的生命周期,及其流程
3. Model 分为几种类型,分别是什么
4. Hap、Har、Hsp 分别是什么,它的特点及其应用场景
这三个都是 HarmonyOS 中的三种不同类型的构建产物,它们在鸿蒙系统中有着不同的作用和特点
- Hap
- 通过 entry 和 feature 类型的 Model 构建来的
- 可以被单独安装和运行
- Har
- 通过 Static Library 类型的 Model 构建来的
- 编译时会被打包进使用到它 Hap/Hsp 包中
- 多包引用相同的 Har 包时,会造成多包间代码和资源的重复
- Hsp
- 通过 Shared Library 类型的 Model 构建来的
- 不会被打包进使用它的 Hap/Hsp 包,而是单独存在
- 当多包需要同时引用同一个共享包时,可以采用 Hsp 替代 Har,能避免 Har 造成的多包间代码和资源的重复拷贝,从而减小应用包大小
5. 简单说下开发阶段、编译阶段、发布阶段的包结构
不建议直接问这个,求职者很难用文字描述来回答
6. 什么是应用模型
应用模型是系统为开发者提供的,开发应用程序必备的组件和运行机制。 有了应用模型,开发者可以基于一套统一的模型进行应用开发,使应用开发更简单、高效
- 应用组件: 是应用的基本单元和运行入口。 用户使用应用时,应用组件会在不同的状态间切换,这些状态称为组件的生命周期。 开发者需要编写组件及其生命周期的回调函数,并在配置文件中进行相关配置。
- 应用进程模型: 定义了应用进程的创建和销毁方式,以及进程间的通信方式。
- 应用线程模型: 规定了进程内线程的创建和销毁方式,以及主线程和UI线程的创建方式和通信方式。
- 应用任务管理模型(仅对系统应用开放): 定义了任务的创建和销毁方式,以及任务与组件的关系。 任务是用户使用应用组件实例的记录。例如,在使用视频应用时,会生成一个视频应用任务,如果启动视频编辑功能,会生成一个视频编辑任务。
- 应用配置文件: 包含应用的配置信息、组件信息、权限信息及开发者自定义信息。 这些信息在编译、分发和运行阶段提供给相应的工具和系统使用。
7. 简单解释下 Stage 模型
- Stage模型是 HarmonyOS 从 API 9开始为开发者新提供的一种应用模型,会是以后主推的模型
- 它的特点是:
- 多个应用组件可以共享同一个ArkTS引擎实例 。这意味着应用组件之间可以方便地共享对象和状态,同时减少内存占用
- Stage模型提供了丰富的生命周期回调函数,开发者可以通过这些回调感知应用的状态变化
- Stage模型采用面向对象的方式,将应用组件以类接口的形式开放给开发者,可以进行派生,利于扩展能力
- 它包含:
- UIAbility 组件 (用于和用户交互)
- ExtensionAbility 组件 (提供特定场景(如卡片、输入法)的扩展能力)
8. 限定词目录匹配的优先级
移动国家码和移动网络码 > 区域(可选组合:语言、语言_文字、语言_国家或地区、语言_文字_国家或地区)> 横竖屏 > 设备类型 > 颜色模式 > 屏幕密度
9. Reusable 是什么
- @Reusable 装饰器装饰的自定义组件,具备运行时可复用的能力
- 这类组件被卸载后,会放在复用缓存里,当再次需要这类组件时,会从缓存中找到,可以对它更新数据后直接添加到组件树中,节省了创建组件节点的时间
- 一般是优化具有大量数据的列表,在快速滚动时的性能时使用,频繁创建和销毁列表项可能导致卡顿和掉帧问题,重用已经创建的列表项视图,可以提高滚动的流畅度
10. 为什么应该避免,在视图里直接改变状态变量,如图所示
- API 9 以后的版本,UI 是以组件为单位更新的,组件上某个属性发生改变时,会更新这个组件整体
- 被状态变量改变影响到的组件,才会发生更新,其它组件不会更新
- 以上代码中,Text 组件的更新,只会发生在 col1 改变后,不会发生在 col2 改变后,因为它没有使用到 col2,所以不会发生更新
11. build() 函数内的语法需要遵守什么限制
- @Entry装饰的自定义组件,其 build() 函数下的根节点唯一且必要,且必须为容器组件
- @Component装饰的自定义组件,其 build() 函数下的根节点唯一且必要,可以为非容器组件
- ForEach 禁止作为根节点
- 不允许使用 switch 语法
- 避免直接在 Text 组件内改变 count 的值
- 不允许调用没有用 @Builder 装饰的方法
- 不允许声明本地变量
- 不允许创建本地作用域
- 不允许 console.info 之类的语句
12. web 和原生组件通信
import { webview } from '@kit.ArkWeb'@Entry
@Component
struct WebComponent {controller: webview.WebviewController = new webview.WebviewController()build() {Column() {// 三种加载网页的方式Web({ src: $rawfile("index.html"), controller: this.controller })Web({ src: "resource://rawfile/index.html", controller: this.controller })Web({ src: 'www.example.com', controller: this.controller }).zoomAccess(false).aspectRatio(1).javaScriptAccess(true).onPageEnd(async e => {// 调用网页内函数并获取返回值const res = await this.controller.runJavaScript('test()')})// 页面上调用 confirm() 函数时触发,以此来实现页面向原生通信.onConfirm(event => {})}}
}// module.json5 访问网络前需要申请网络权限
"module": {"requestPermissions": [{"name": "ohos.permission.INTERNET"}]}
13. 持久化存储
preference: preferences.Preferencesthis.preference = preferences.getPreferences(getContext(this), 'my-preference')// 读取,异步的方法,也有 getSync 这样同步的方法
const res = await this.preference.get(key, defaultValue)// 写入
this.preference.put('accountInfo', response)// 写到文件
this.preference.flush()// 清空
this.preference.clear()
14. Worker
Worker 能创建独立线程,一般用来处理一些比较耗时的操作,避免在大量计算时阻塞主线程的运行 Worker 线程不支持UI操作 Worker 线程一旦被创建则不会主动被销毁,在一定程度上会造成资源的浪费,应及时关闭空闲的 Worker 创建Worker的线程称之为宿主线程,Worker自身的线程称之为Worker线程。创建Worker传入的url文件在Worker线程中执行,
import { worker } from '@kit.ArkTS'// 主要说明以下两种场景:const workerStageModel01 = new worker.ThreadWorker('entry/ets/workers/worker.ets', {name:"first worker in Stage model"});const workerStageModel02 = new worker.ThreadWorker('phone/ets/ThreadFile/workers/worker.ets');// 向宿主线程发送消息
workerStageModel02.postMessage()
14. Worker 和 TaskPool 的区别
重点放最后
随着鸿蒙5.0的推出,市场上的鸿蒙开发岗位也随之增加;许多程序员开始面向鸿蒙岗位,但是网上的面试题几乎看不到。
作为最早一批学鸿蒙开发的我,整理了自己以及开发群友面试所问到的题目。
为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!