2024最新鸿蒙开发口试题合集(一)-HarmonyOS NEXT Release(API 12 Releas ...

打印 上一主题 下一主题

主题 810|帖子 810|积分 2430

1. HarmonyOS应用打包后的文件扩展名是?

打包后的文件扩展名为.hap(HarmonyOS Ability Package),这是HarmonyOS应用的标准包格式
2. 页面和自定义组件生命周期有哪些?

页面和自定义组件生命周期说明
有@Entry装饰器的@component组件的生命周期


  • onPageShow:页面每次显示时触发一次,包括路由过程、应用进入前台等场景。
  • onPageHide:页面每次隐藏时触发一次,包括路由过程、应用进入配景等场景。
  • onBackPress:当用户点击返回按钮时触发。
有@Entry装饰器和无@Entry装饰器@Component组件都有的生命周期


  • aboutToAppear:组件即将出现时回调该接口,详细时机为在创建自定义组件的新实例后,在实行其 build()函数之前实行。
  • onDidBuild:API12新增,组件 build()函数实行完成之后回调该接口,不建议在 onDidBuild函数中更改状态变量、使用 animateTo等功能,这会导致不稳定的UI表现。
  • aboutToDisappear:aboutToDisappear函数在自定义组件析构烧毁之前实行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改会导致应用步伐行为不稳定。
3. 怎样进行数据持久化?

应用数据持久化

  • 用户首选项(Preferences):这是一种轻量级的配置数据持久化方式,实用于保存应用配置信息、用户偏好设置等。它通过文本形式保存数据,而且数据会全量加载到内存中,因此访问速率快,但不得当存储大量数据。
  • 键值型数据库(KV-Store):实用于存储布局简单的数据,如商品名称和代价、员工工号和出勤状态等。键值型数据库以“键值对”的形式组织数据,得当数据关系不复杂的场景。
  • 关系型数据库(RelationalStore):基于SQLite,实用于存储包含复杂关系的数据,如弟子信息、雇员信息等。关系型数据库提供了一系列SQL操作,如增编削查等。
4. 怎样进行全局状态管理?

应用全局的UI状态存储
1. @Provide+@Consume装饰器


  • 实用场景:实用于整个组件树而言“全局”的状态共享,且该状态改动不频繁的场景。
  • 工作原理:通过在最顶层组件中使用 @Provide装饰器提供状态,其他需要共享状态的组件通过 @Consume装饰器获取该状态 。
  • 优点:减少了状态传递的层级,提升了代码的可维护性和可拓展性。
  • 注意事项:确保状态的生命周期与组件树的生命周期一致,制止不必要的UI刷新。
2. AppStorage


  • 实用场景:实用于整个应用而言“全局”的变量或应用的主线程内多个 UIAbility实例间的状态共享。
  • 工作原理:AppStorage与应用的进程绑定,由UI框架在应用步伐启动时创建,当应用进程制止,AppStorage被采取。
  • 优点:实用于需要在整个应用中共享状态的场景。
  • 注意事项:确保状态的生命周期与应用进程一致,制止在应用退出后仍有状态存在。
3. LocalStorage


  • 实用场景:实用于单个Ability而言“全局”的变量,重要用于不同页面间的状态共享。
  • 工作原理:LocalStorage的生命周期由应用步伐决定,当应用释放最后一个指向 LocalStorage的引用时,LocalStorage被垃圾采取。
  • 优点:实用于需要在单个UIAbility中不同页面间共享状态的场景。
  • 注意事项:确保状态的生命周期与应用步伐的生命周期一致,制止在应用退出后仍有状态存在。

5. LocalStorage在应用重启后数据会消散吗?


页面级UI状态存储

因为LocalStorage 是一种用于页面或组件级别的数据存储方式,它允许开发者在页面或组件的生命周期内存储和检索数据。LocalStorage 的数据存储在内存中,因此它的读写速率相对较快。但是,当应用重启后,LocalStorage 中的数据会丢失。
6. 父子组件怎样通信?

 
@Prop装饰器、@Link装饰器、@Provide和@Consume装饰器、@Event装饰器、@Parame装饰器、@Provider装饰器和@Consumer装饰器
当前(API 12)状态管理有两个版本 @Component和 @ComponentV2
1. 父子单向数据传递 @State+@Prop
@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变革不会同步回其父组件。
2. 父子双向数据传递 @State+@Link 、@objectLink+@Link
子组件中被 @Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。
3. 跨组件通信 @Provide装饰器和 @Consume装饰器
@Provide和 @Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于 @Prop和 @Link,@Provide和 @Consume摆脱参数传递机制的束缚,实现跨层级传递。
4. @Observed装饰器和 @ObjectLink装饰器
对于多层嵌套的情况,好比二维数组,或者数组项class,或者class的属性是class,他们的第二层的属性变革是无法观察到的。这就要用到 @Observed/@ObjectLink装饰器
   注意ObjectLink装饰器不能在 @Entry装饰的自定义组件中使用且 @ObjectLink 装饰的变量不能被赋值,只能对其属性进行赋值操作
  
7. 兄弟组件怎样通信?



1. 通过公共父组件传递
如果两个组件是同一个父组件的子组件,可以通过父组件来传递数据或事件。父组件可以作为中介,将一个子组件的数据或事件传递给另一个子组件。
2. 使用全局状态管理
使用全局状态管理(如 AppStorage、LocalStorage)来存储共享数据。兄弟组件可以独立地读取和更新这个全局状态,从而实现通信。
8. 怎样实现页面间的通信?

1.使用 @Provide和 @Consume装饰器(见6.3)
2.使用路由跳转传参
  1. import { router } from '@kit.ArkUI';
  2. router.pushUrl({
  3.   url: 'pages/Detail', // 目标url
  4.    params: paramsInfo // 添加params属性,传递自定义参数
  5. })
  6. // 返回指定页面并携带参数
  7. router.back({
  8.   url: 'pages/Home',
  9.   params: {
  10.     info: '来自Home页'
  11.   }
  12. });
复制代码
3.使用导航跳转传参
  1. this.pageStack.pushPath({ name: "PageOne", param: "PageOne Param" })
  2. this.pageStack.pushPathByName("PageOne", "PageOne Param")
复制代码
9. Navigation组件跳转和router跳转有什么区别?


官方文档写了很多,捡几个我觉得比力重要的写的

  • Navigation:是路由容器组件,实用于模块内和跨模块的路由切换,一次开发,多端部署场景。Router位于页面栈管理节点 stage 下面,不提供导航容器的概念。
  • Navigation和 Router都支持跳转传参,但 Router对象中暂不支持方法变量。
  • Navigation:支持清算指定路由,页面栈没有上限,可以无穷跳转。Router不支持清算指定路由且页面栈最大为32,页面栈到达32之后必须打扫之后才气继承跳转。
  • Navigation:支持自定义转场动画和共享元素转场动画。 Router:仅支持简单自定义转场动画。
  • Navigation:支持通过 setInterception 方法设置路由拦截。Router:不支持路由拦截。
  • Navigation:支持沉浸式页面和模态嵌套路由。Router:不支持,需要通过窗口配置实现沉浸式页面。
总而言之,Navigation 组件在功能上更具丰富性和机动性,特别是在处理复杂的导航布局、动效和路由管理方面。
而 Router 则提供了更基础的路由跳转功能,得当简单的路由需求。开发者可以根据应用的详细需求和设计选择最符合的路由方案。
详细的区别如下表:
10. HarmonyOS与Android和iOS有什么区别?


HarmonyOS 是华为开发的一个开源、分布式的操作体系。它设计用于多种装备,包括智能手机、平板电脑、智能电视和物联网装备。与Android和iOS的重要区别在于:
   

  • 分布式架构:HarmonyOS支持跨装备无缝协作,允许装备之间共享硬件资源。
  • 性能:HarmonyOS优化了使命调度和内存管理,进步了性能和响应速率。
  • 安全性:HarmonyOS接纳了多条理的安全战略,包括数据加密和安全启动。
  • 生态体系:HarmonyOS正在构建自己的应用生态体系,鼓励开发者使用Ark Ts和ArkUI框架。
  
11. 什么是Ability?



Ability是应用/服务所具备的能力的抽象,一个Module可以包含一个或多个 Ability ,在鸿蒙体系中,Ability提供了对 Ability生命周期、上下文情况等调用管理的能力,包括 Ability创建、烧毁、转储客户端信息等
鸿蒙体系中的 Ability重要分为两种范例:UIAbility和 ExtensionAbility。
1. UIAbility :


  • 定义 :包含UI界面,提供展示UI的能力,重要用于和用户交互 。
  • 创建 :在模块中添加UIAbility时,选中对应的模块,单击鼠标右键,选择New > Ability,设置Ability名称,选择是否在装备主屏幕上显示该功能的启动图标,单击Finish完成Ability创建 。
2. ExtensionAbility :


  • 定义 :提供特定场景的扩展能力,满足更多的使用场景 。
  • 创建 :在模块中添加ExtensionAbility时,选中对应的模块,单击鼠标右键,选择不同的场景范例(如Accessibility、EmbeddedUIExtensionAbility等) 。当前仅Application工程支持创建ExtensionAbility。设置Ability名称,单击Finish完成ExtensionAbility创建。

此外,Ability是Ability模块的基类,提供体系配置更新回调和体系内存调解回调 。Ability的继承关系包括UIAbility和ExtensionAbility等详细类.
总之,Ability是鸿蒙体系中用于管理应用能力的核心组件,通过不同范例的Ability可以实现不同的功能需求。
12. ArkUI框架有哪些特点?

ArkUI框架是鸿蒙(HarmonyOS)中的一个重要组件框架,具有以下几个特点:

  • 组件树布局 : ArkUI框架通过布局组件和基础组件构建界面描述树(组件树),其中基础组件为叶子节点,布局组件为中间节点 。当用户进行交互时,会触发界面修改,通过重新渲染组件树来实现应用界面更新 。
  • 数据与UI更新过程 : ArkUI框架的数据处理过程和UI更新过程是分开进行的。数据处理过程中,重要是对状态数据进行更新,并通过标脏过程确定布局最小影响范围,减少不必要的重新布局 。UI更新过程包括组件标脏、布局、丈量和渲染等阶段 。
  • 布局组件 : ArkUI框架提供了多种布局组件,如Row、Column、Stack、Flex、List、Grid、RelativeContainer等。开发者可以根据场景选择符合的布局组件,以优化性能 。比方,线性布局(Row、Column)实用于横向或纵向排列组件,而弹性布局(Flex)实用于需要弹性排列的场景。
  • 性能优化 : ArkUI框架在性能优化方面做了很多工作。比方,通过减少不必要的组件嵌套和节点数目,降低布局测算的复杂度,从而提升性能。开发者可以使用DevEco Studio提供的工具(如Profiler和ArkUI Inspector)来查看性能瓶颈和组件树布局,进一步优化应用性能。
  • 状态管理 : ArkUI框架支持状态管理最佳实践,通过有效的状态管理减少无效的UI更新操作,提升性能。比方,在状态变量变革导致UI更新时,只更新部门组件,而不是重新渲染整个界面。
13. 跨装备通信的方式有哪些?

HarmonyOS支持多种跨装备通信方式,包括:


  • 分布式软总线:一种高性能的通信机制,允许装备之间建立直接毗连,进行数据传输。
  • 蓝牙:使用标准的蓝牙技术进行装备间的通信。
  • 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依然可见。以下是实现步骤
1. 设置窗口属性:
在应用的入口Ability中,可以通过设置窗口属性来实现沉浸式模式。这通常涉及到配置窗口特性(Window Features)来隐藏状态栏和导航栏。
2. 使用体系API:
鸿蒙OS提供了API来控制体系UI的显示和隐藏。你可以在应用的代码中调用这些API来实现沉浸式效果。
3. 配置应用的配置文件:
在应用的config.json或其他配置文件中,可以声明应用需要的窗口特性,如ohos:immersive。
4. 动态切换:
应用可以根据用户的交互或特定场景动态地进入或退出沉浸式模式。这可能涉及到监听用户的手势或其他事件来切换UI状态。
5. 适配不同装备:
不同的装备可能有不同的屏幕和体系UI,因此在实现沉浸式模式时,需要考虑不同装备的适配标题。

24. 怎样获取屏幕的安全地区?




  • 可以通过设置组件的expandSafeArea属性来获取获取UIWindow:首先,你需要获取到当前页面的UIWindow实例。
  • 调用getSafeArea方法:通过UIWindow实例调用getSafeArea方法来获取安全地区的Rect对象。
示例:
  1. import ohos.aafwk.ability.AbilitySlice;
  2. import ohos.aafwk.content.Intent;
  3. import ohos.agp.window.UIWindow;
  4. import ohos.agp.utils.Rect;
  5. public class MyAbilitySlice extends AbilitySlice {
  6.     @Override
  7.     public void onStart(Intent intent) {
  8.         super.onStart(intent);
  9.         setUIContent(new SurfaceLayout(this));
  10.         UIWindow window = getUIWindow();
  11.         if (window != null) {
  12.             // 获取安全区域
  13.             Rect safeArea = window.getSafeArea();
  14.             // 在这里可以使用safeArea对象,它包含了安全区域的位置和尺寸信息
  15.             // 例如,可以使用safeArea.left, safeArea.top, safeArea.right, safeArea.bottom
  16.         }
  17.     }
  18. }
复制代码
25. ArkTs是什么?

ArkTs介绍
ArkTS是HarmonyOS优选的主力应用开发语言。保持了TypeScript的根本风格,同时通过规范定义强化开发期静态检查和分析,提升步伐实行稳定性和性能。

ArkTS的重要特点包括:


  • 静态范例检查:ArkTS在编译时进行范例检查,这有助于在代码运行前发现和修复错误,进步代码的稳定性和性能。
  • 声明式UI:ArkTS定义了声明式UI描述,允许开发者以更简洁、更自然的方式开发跨端应用。
  • 状态管理:ArkTS提供了多维度的状态管理机制,使得与UI相关联的数据可以在组件内使用,也可以在不同组件层级间传递,支持单向和双向数据流。
  • 渲染控制:ArkTS支持条件渲染、循环渲染和数据懒加载,允许开发者根据应用的不同状态渲染UI内容。
  • 兼容性:ArkTS兼容TS/JavaScript生态,开发者可以使用TS/JS进行开发或复用已有代码。
  • 并发机制:ArkTS支持轻量化的并发机制,允许开发者编写并发代码,进步应用的性能和响应速率。

26. ArkTs与TypeScript有什么区别?(答5点以上)


ArkTs官方文档
ArkTS 是基于 TypeScript 开发的框架,但是有一些限定和差异。ArkTS 旨在提供更严格的范例检查和优化的代码性能,同时确保与 HarmonyOS 的开发情况和特性兼容。以下是 ArkTS 与 TypeScript 的差异:


  • 不支持使用对象字面量声明范例。
  • 不支持使用 var关键字。
  • 不支持使用 in运算符。
  • 不支持导入断言。
  • 不支持使用 any范例。
  • 不支持使用 import赋值表达式。
  • 不支持使用 require导入

详细区别:
   

  • 生成器函数: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的区别?

@Provider和@Consumer 官方文档
28. @Prop和@ObjectLink装饰器有什么区别?

1.用途


  • @Prop装饰器:重要用于在组件之间传递数据,将父组件的值传递给子组件。它定义了子组件的属性,可以接收来自父组件的赋值。@ObjectLink用于建立对象之间的链接,通常用于在组件内部或组件之间共享和同步状态。它可以将一个对象的属性与另一个对象的属性进行链接,当一个对象的属性发生变革时,另一个对象的属性也会自动更新。
2. 数据传递方式


  • @Prop:是单向的数据传递,从父组件到子组件。父组件可以设置子组件的 @Prop属性值,但子组件不能直接修改这个值。@ObjectLink是双向的数据传递,父组件和子组件都可以修改子组件的 @ObjectLink属性值。
3. 性能


  • @Prop会深拷贝数据,具有拷贝的性能开销,性能低于 @ObjectLink详见官方文档。
29. ForEach和LazyForEach的区别?

ForEach和LazyForEach都是用于渲染列表的装饰器,它们的区别在于:


  • ForEach:渲染列表时,会将列表中的每一项都渲染一次,实用于列表项数目较少的情况。
  • LazyForEach:渲染列表时,只渲染当前可见的列表项,实用于列表项数目较多的情况。
30. UIAbility的生命周期有哪些?

官方文档说明
UIAbility的生命周期包括Create、Foreground、Background、Destroy四个状态
31. H5怎样与HarmonyOS应用(webView)进行通信?官方文档



  • 应用侧调用前端页面JS函数
应用侧可以通过runJavaScript()方法异步调用前端页面的JavaScript相关函数,并通过Promise方式返回脚本实行的效果。runJavaScript需要在loadUrl完成后,好比onPageEnd中调用。


  • 前端页面调用应用侧函数
使用Web组件将应用侧代码注册到前端页面中,注册完成之后,前端页面中使用注册的对象名称就可以调用应用侧的函数,实如今前端页面中调用应用侧方法。注册应用侧代码有两种方式,一种在Web组件初始化调用,使用javaScriptProxy()接口。另外一种在Web组件初始化完成后调用,使用registerJavaScriptProxy()接口。
32. 怎样实现图片上传?

有两种方式原生和Web组件:


  • 原生:使用上传下载模块(ohos.request)的上传接口将当地文件(图片)上传,需声明权限:ohos.permission.INTERNET。
代码示例:
  1. // pages/xxx.ets
  2. import { common } from '@kit.AbilityKit';
  3. import fs from '@ohos.file.fs';
  4. import { BusinessError, request } from '@kit.BasicServicesKit';
  5. // 获取应用文件路径
  6. let context = getContext(this) as common.UIAbilityContext;
  7. let cacheDir = context.cacheDir;
  8. // 新建一个本地应用文件
  9. let file = fs.openSync(cacheDir + '/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  10. fs.writeSync(file.fd, 'upload file test');
  11. fs.closeSync(file);
  12. // 上传任务配置项
  13. let header = new Map<Object, string>();
  14. header.set('key1', 'value1');
  15. header.set('key2', 'value2');
  16. let files: Array<request.File> = [
  17. //uri前缀internal://cache 对应cacheDir目录
  18.   { filename: 'test.txt', name: 'test', uri: 'internal://cache/test.txt', type: 'txt' }
  19. ]
  20. let data: Array<request.RequestData> = [{ name: 'name', value: 'value' }];
  21. let uploadConfig: request.UploadConfig = {
  22.   url: 'https://xxx',
  23.   header: header,
  24.   method: 'POST',
  25.   files: files,
  26.   data: data
  27. }
  28. // 将本地应用文件上传至网络服务器
  29. try {
  30.   request.uploadFile(context, uploadConfig)
  31.     .then((uploadTask: request.UploadTask) => {
  32.       uploadTask.on('complete', (taskStates: Array<request.TaskState>) => {
  33.         for (let i = 0; i < taskStates.length; i++) {
  34.           console.info(`upload complete taskState: ${JSON.stringify(taskStates[i])}`);
  35.         }
  36.       });
  37.     })
  38.     .catch((err: BusinessError) => {
  39.       console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
  40.     })
  41. } catch (error) {
  42.   let err: BusinessError = error as BusinessError;
  43.   console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
  44. }
复制代码


  • 使用axios上传:使用axios上传文件,需安装axios依靠。
注意事项

  • 上传文件需要单独导入FormData模块
  • 当前版本只支持 Stage 模型
  • 上传范例支持uri和ArrayBuffer,uri支持“internal”协议范例和沙箱路径,仅支持"internal"协议范例,"internal://cache/"为必填字段,示例: internal://cache/path/to/file.txt;沙箱路径示例:cacheDir + ‘/hello.txt’
  • 请求的表单数据值为string范例
  • 支持设置多部门表单数据的数据名称和数据范例范例
  • 上传参数context:当uri为沙箱路径,无需传参context;若uri为“internal”协议范例,必须传参context
当上传的内容为ArrayBuffer时,用法如下
  1. import axios from '@ohos/axios'
  2. import { FormData } from '@ohos/axios'
  3. import fs from '@ohos.file.fs';
  4. // ArrayBuffer
  5. let formData = new FormData()
  6. let cacheDir = getContext(this).cacheDir
  7. try {
  8.   // 写入
  9.   let path = cacheDir + '/hello.txt';
  10.   let file = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
  11.   fs.writeSync(file.fd, "hello, world"); // 以同步方法将数据写入文件
  12.   fs.fsyncSync(file.fd); // 以同步方法同步文件数据。
  13.   fs.closeSync(file.fd);
  14.   // 读取
  15.   let file2 = fs.openSync(path, 0o2);
  16.   let stat = fs.lstatSync(path);
  17.   let buf2 = new ArrayBuffer(stat.size);
  18.   fs.readSync(file2.fd, buf2); // 以同步方法从流文件读取数据。
  19.   fs.fsyncSync(file2.fd);
  20.   fs.closeSync(file2.fd);
  21.   formData.append('file', buf2);
  22.   // formData.append('file', buf2, { filename: 'text.txt', type: 'text/plain'}); 设置多部分表单数据的数据名称和数据类型类型
  23. } catch (err) {
  24.   console.info('err:' + JSON.stringify(err));
  25. }
  26. // 发送请求
  27. axios.post<string, AxiosResponse<string>, FormData>(this.uploadUrl, formData, {
  28.   headers: { 'Content-Type': 'multipart/form-data' },
  29.   context: getContext(this),
  30.   onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
  31.   console.info(progressEvent && progressEvent.loaded && progressEvent.total ? Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%');
  32. },
  33. }).then((res: AxiosResponse) => {
  34.   console.info("result" + JSON.stringify(res.data));
  35. }).catch((error: AxiosError) => {
  36.   console.error("error:" + JSON.stringify(error));
  37. })
复制代码
当上传的uri时,用法如下
  1. import axios from '@ohos/axios'
  2. import { FormData } from '@ohos/axios'
  3. let formData = new FormData()
  4. formData.append('file', 'internal://cache/blue.jpg')
  5. // formData.append('file', cacheDir + '/hello.txt'); uri支持传入沙箱路径
  6. // 发送请求
  7. axios.post<string, AxiosResponse<string>, FormData>('https://www.xxx.com/upload', formData, {
  8.   headers: { 'Content-Type': 'multipart/form-data' },
  9.   context: getContext(this),
  10.   onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
  11.     console.info(progressEvent && progressEvent.loaded && progressEvent.total ? Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%');
  12.   },
  13. }).then((res: AxiosResponse<string>) => {
  14.   console.info("result" + JSON.stringify(res.data));
  15. }).catch((err: AxiosError) => {
  16.   console.error("error:" + JSON.stringify(err));
  17. })
复制代码
33.hap、har、hsp三者的区别?



  • HAP(Harmony Ability Package)是应用安装和运行的根本单位。HAP包是由代码、资源、第三方库、配置文件等打包生成的模块包,其重要分为两种范例:entry和feature。(又称ability)
  • HAR(Harmony Archive)是静态共享包,可以包含代码、C++库、资源和配置文件。通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。(又称static library, 静态共享包)
  • HSP(Harmony Shared Package)是动态共享包,可以包含代码、C++库、资源和配置文件,通过HSP可以实当代码和资源的共享。HSP不支持独立发布,而是跟随其宿主应用的APP包一起发布,与宿主应用同进程,具有相同的包名和生命周期。(又称shared library, 动态共享包)
34. 鸿蒙常用的装饰器有哪些?



  • @State 定义状态,当前组件能使用
  • @Prop 父子组件通信(特点:子组件数据不能修改)
  • @Link 父子组件通信(特点:子组件数据可以修改)
  • @Observed 和 @ObjectLink 父子组件通信(特点:嵌套第二层数据修改可以到达响应式,之前方案不行)
  • @Provide 和 @Consume 祖孙组件通信
  • @Builder 和 @BuilderParam 父子组件通信,通信组件数据
  • @Watch 监视数据的变革(第一次不会触发)
35. 怎样启动一个 ability?

通过 context 对象的 startAbility 方法官方文档:
  1. import { common, Want } from '@kit.AbilityKit';
  2. import { BusinessError } from '@kit.BasicServicesKit';
  3. context = getContext(this) as common.UIAbilityContext; // UIAbilityContext
  4. const want: Want = {
  5.   deviceId: '', // deviceId为空表示本设备
  6.   bundleName: 'com.example.system', // AppScope/app.json5 中找
  7.   abilityName: 'SecondAbility', // 去对应的ability内部找module.json5
  8.   // moduleName: 'entry' // moduleName非必选
  9.   parameters: { // 携带参数
  10.   }
  11. };
  12. this.context.startAbility(want, (err: BusinessError) => {
  13.   if (err.code) {
  14.     // 显式拉起Ability,通过bundleName、abilityName和moduleName可以唯一确定一个Ability
  15.     console.error(`Failed to startAbility. Code: ${err.code}, message: ${err.message}`);
  16.   }
  17. });
复制代码
36. 显示 want 和 隐式 want 的区别?

官方文档


  • 显式Want:在启动目标应用组件时,调用方传入的want参数中指定了abilityName和bundleName,称为显式Want。显式Want通常用于应用内组件启动,通过在Want对象内指定本应用Bundle名称信息(bundleName)和abilityName来启动应用内目标组件。当有明确处理请求的对象时,显式Want是一种简单有效的启动目标应用组件的方式。比方:打开其他窗口
  • 隐式Want:在启动目标应用组件时,调用方传入的want参数中未指定abilityName,称为隐式Want。当需要处理的对象不明确时,可以使用隐式Want,在当前应用中使用其他应用提供的某个能力,而不关心提供该能力的详细应用。隐式Want使用skills标签来定义需要使用的能力,并由体系匹配声明支持该请求的所有应用来处理请求。比方,需要打开一个链接的请求,体系将匹配所有声明支持该请求的应用,然后让用户选择使用哪个应用打开链接。比方:将pdf文件传递给其他应用窗口
总的来说


  • 显示want和隐式want的区别在于有无abilityName。有就是显示want,没有就是隐式want
  • 显示want重要用于当前应用窗口跳转,隐式want打开其他应用的窗口

37. 三层架构是什么?


官方文档

三层架构为了“一次开发,多端部署”,项目布局接纳三层架构
三层工程布局如下:


  • commons(公共能力层):用于存放公共基础能力聚集(如工具库、公共配置等)。commons层可编译成一个或多个HAR包或HSP包,只可以被products和features依靠,不可以反向依靠。
  • features(基础特性层):开发页面、组件(HAR包或HSP包)。
  • products(产物定制层):定义phone\pad两个ability,引用 features 的包和 commons 的包完成应勤奋能

38. 优化内存有哪些方法?


官方文档
1. 使用onMemoryLevel监听内存变革
2. 使用LRUCache优化ArkTS内存
比方:我们搜刮租房列表可以无穷加载租房数据,这样数据会越来越多,我们使用LRUCacheUtil来管理数据
3. 使用生命周期管理优化ArkTS内存
比方:aboutToDisappear中烧毁订阅事件,打扫定时器等
4.使用purgeable优化C++内存
39. 多线程实现方式TaskPoll和Worker的区别?


  • TaskPool和Worker均支持多线程并发能力。由于TaskPool的工作线程会绑定体系的调度优先级,而且支持负载平衡(自动扩缩容),而Worker需要开发者自行创建,存在创建耗时以及不支持设置调度优先级,故在性能方面使用TaskPool会优于Worker,因此大多数场景推荐使用TaskPool。
  • TaskPool方向独立使命维度,该使命在线程中实行,无需关注线程的生命周期,超长使命(大于3分钟且非长时使命)会被体系自动采取;而Worker方向线程的维度,支持长时间占据线程实行,需要自动管理线程生命周期。
40. 音视频的组件的使用方式?



  • 视频组件 Video
  1. controller: VideoController = new VideoController()
  2. Video({
  3.   src: $rawfile('test.mp4'),
  4.   previewUri: $r('app.media.startIcon'),
  5.   controller: this.controller
  6. })
  7. .width('100%')
  8. .height(200)
  9. .autoPlay(true)
  10. .controls(true)
复制代码


  • 音频组件 Audio 官方文档(了解)
  1. //配置音频渲染参数并创建AudioRenderer实例,音频渲染参数的详细信息可以查看AudioRendererOptions。
  2. import { audio } from '@kit.AudioKit';
  3. let audioStreamInfo: audio.AudioStreamInfo = {
  4.   samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率
  5.   channels: audio.AudioChannel.CHANNEL_2, // 通道
  6.   sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式
  7.   encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式
  8. };
  9. let audioRendererInfo: audio.AudioRendererInfo = {
  10.   usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION,
  11.   rendererFlags: 0
  12. };
  13. let audioRendererOptions: audio.AudioRendererOptions = {
  14.   streamInfo: audioStreamInfo,
  15.   rendererInfo: audioRendererInfo
  16. };
  17. audio.createAudioRenderer(audioRendererOptions, (err, data) => {
  18.   if (err) {
  19.     console.error(`Invoke createAudioRenderer failed, code is ${err.code}, message is ${err.message}`);
  20.     return;
  21.   } else {
  22.     console.info('Invoke createAudioRenderer succeeded.');
  23.     let audioRenderer = data;
  24.   }
  25. });
  26. // 调用on('writeData')方法,订阅监听音频数据写入回调。
  27. import { BusinessError } from '@kit.BasicServicesKit';
  28. import { fileIo } from '@kit.CoreFileKit';
  29. let bufferSize: number = 0;
  30. class Options {
  31.   offset?: number;
  32.   length?: number;
  33. }
  34. let path = getContext().cacheDir;
  35. //确保该路径下存在该资源
  36. let filePath = path + '/StarWars10s-2C-48000-4SW.wav';
  37. let file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY);
  38. let writeDataCallback = (buffer: ArrayBuffer) => {
  39.   let options: Options = {
  40.     offset: bufferSize,
  41.     length: buffer.byteLength
  42.   }
  43.   fileIo.readSync(file.fd, buffer, options);
  44.   bufferSize += buffer.byteLength;
  45. }
  46. audioRenderer.on('writeData', writeDataCallback);
  47. //调用start()方法进入running状态,开始渲染音频。
  48. import { BusinessError } from '@kit.BasicServicesKit';
  49. audioRenderer.start((err: BusinessError) => {
  50.   if (err) {
  51.     console.error(`Renderer start failed, code is ${err.code}, message is ${err.message}`);
  52.   } else {
  53.     console.info('Renderer start success.');
  54.   }
  55. });
  56. //调用stop()方法停止渲染。
  57. import { BusinessError } from '@kit.BasicServicesKit';
  58. audioRenderer.stop((err: BusinessError) => {
  59.   if (err) {
  60.     console.error(`Renderer stop failed, code is ${err.code}, message is ${err.message}`);
  61.   } else {
  62.     console.info('Renderer stopped.');
  63.   }
  64. });
  65. // 调用release()方法销毁实例,释放资源。
  66. import { BusinessError } from '@kit.BasicServicesKit';
  67. audioRenderer.release((err: BusinessError) => {
  68.   if (err) {
  69.     console.error(`Renderer release failed, code is ${err.code}, message is ${err.message}`);
  70.   } else {
  71.     console.info('Renderer released.');
  72.   }
  73. });
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

光之使者

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表