營銷導(dǎo)向企業(yè)網(wǎng)站策劃java培訓(xùn)
1. HarmonyOS應(yīng)用打包后的文件擴展名是?
打包后的文件擴展名為.hap(HarmonyOS Ability Package),這是HarmonyOS應(yīng)用的標準包格式
2. 頁面和自定義組件生命周期有哪些?
頁面和自定義組件生命周期說明
有@Entry裝飾器的@component組件的生命周期
- onPageShow:頁面每次顯示時觸發(fā)一次,包括路由過程、應(yīng)用進入前臺等場景。
- onPageHide:頁面每次隱藏時觸發(fā)一次,包括路由過程、應(yīng)用進入后臺等場景。
- onBackPress:當用戶點擊返回按鈕時觸發(fā)。
有@Entry裝飾器和無@Entry裝飾器@Component組件都有的生命周期
- aboutToAppear:組件即將出現(xiàn)時回調(diào)該接口,具體時機為在創(chuàng)建自定義組件的新實例后,在執(zhí)行其 build()函數(shù)之前執(zhí)行。
- onDidBuild:API12新增,組件 build()函數(shù)執(zhí)行完成之后回調(diào)該接口,不建議在 onDidBuild函數(shù)中更改狀態(tài)變量、使用 animateTo等功能,這會導(dǎo)致不穩(wěn)定的UI表現(xiàn)。
- aboutToDisappear:aboutToDisappear函數(shù)在自定義組件析構(gòu)銷毀之前執(zhí)行。不允許在aboutToDisappear函數(shù)中改變狀態(tài)變量,特別是@Link變量的修改會導(dǎo)致應(yīng)用程序行為不穩(wěn)定。
3. 如何進行數(shù)據(jù)持久化?
應(yīng)用數(shù)據(jù)持久化
- 用戶首選項(Preferences):這是一種輕量級的配置數(shù)據(jù)持久化方式,適用于保存應(yīng)用配置信息、用戶偏好設(shè)置等。它通過文本形式保存數(shù)據(jù),并且數(shù)據(jù)會全量加載到內(nèi)存中,因此訪問速度快,但不適合存儲大量數(shù)據(jù)。
- 鍵值型數(shù)據(jù)庫(KV-Store):適用于存儲結(jié)構(gòu)簡單的數(shù)據(jù),如商品名稱和價格、員工工號和出勤狀態(tài)等。鍵值型數(shù)據(jù)庫以“鍵值對”的形式組織數(shù)據(jù),適合數(shù)據(jù)關(guān)系不復(fù)雜的場景。
- 關(guān)系型數(shù)據(jù)庫(RelationalStore):基于SQLite,適用于存儲包含復(fù)雜關(guān)系的數(shù)據(jù),如學(xué)生信息、雇員信息等。關(guān)系型數(shù)據(jù)庫提供了一系列SQL操作,如增刪改查等。
4. 如何進行全局狀態(tài)管理?
應(yīng)用全局的UI狀態(tài)存儲
1. @Provide+@Consume裝飾器
- 適用場景:適用于整個組件樹而言“全局”的狀態(tài)共享,且該狀態(tài)改動不頻繁的場景。
- 工作原理:通過在最頂層組件中使用 @Provide裝飾器提供狀態(tài),其他需要共享狀態(tài)的組件通過 @Consume裝飾器獲取該狀態(tài) 。
- 優(yōu)點:減少了狀態(tài)傳遞的層級,提升了代碼的可維護性和可拓展性。
- 注意事項:確保狀態(tài)的生命周期與組件樹的生命周期一致,避免不必要的UI刷新。
2. AppStorage
- 適用場景:適用于整個應(yīng)用而言“全局”的變量或應(yīng)用的主線程內(nèi)多個 UIAbility實例間的狀態(tài)共享。
- 工作原理:AppStorage與應(yīng)用的進程綁定,由UI框架在應(yīng)用程序啟動時創(chuàng)建,當應(yīng)用進程終止,AppStorage被回收。
- 優(yōu)點:適用于需要在整個應(yīng)用中共享狀態(tài)的場景。
- 注意事項:確保狀態(tài)的生命周期與應(yīng)用進程一致,避免在應(yīng)用退出后仍有狀態(tài)存在。
3. LocalStorage
- 適用場景:適用于單個Ability而言“全局”的變量,主要用于不同頁面間的狀態(tài)共享。
- 工作原理:LocalStorage的生命周期由應(yīng)用程序決定,當應(yīng)用釋放最后一個指向 LocalStorage的引用時,LocalStorage被垃圾回收。
- 優(yōu)點:適用于需要在單個UIAbility中不同頁面間共享狀態(tài)的場景。
- 注意事項:確保狀態(tài)的生命周期與應(yīng)用程序的生命周期一致,避免在應(yīng)用退出后仍有狀態(tài)存在。
5. LocalStorage在應(yīng)用重啟后數(shù)據(jù)會消失嗎?
頁面級UI狀態(tài)存儲
會
因為LocalStorage 是一種用于頁面或組件級別的數(shù)據(jù)存儲方式,它允許開發(fā)者在頁面或組件的生命周期內(nèi)存儲和檢索數(shù)據(jù)。LocalStorage 的數(shù)據(jù)存儲在內(nèi)存中,因此它的讀寫速度相對較快。但是,當應(yīng)用重啟后,LocalStorage 中的數(shù)據(jù)會丟失。
6. 父子組件如何通信?
?
@Prop裝飾器、@Link裝飾器、@Provide和@Consume裝飾器、@Event裝飾器、@Parame裝飾器、@Provider裝飾器和@Consumer裝飾器
當前(API 12)狀態(tài)管理有兩個版本 @Component和 @ComponentV2
1. 父子單向數(shù)據(jù)傳遞 @State+@Prop
@Prop裝飾的變量可以和父組件建立單向的同步關(guān)系。@Prop裝飾的變量是可變的,但是變化不會同步回其父組件。
2. 父子雙向數(shù)據(jù)傳遞 @State+@Link 、@objectLink+@Link
子組件中被 @Link裝飾的變量與其父組件中對應(yīng)的數(shù)據(jù)源建立雙向數(shù)據(jù)綁定。
3. 跨組件通信 @Provide裝飾器和 @Consume裝飾器
@Provide和 @Consume,應(yīng)用于與后代組件的雙向數(shù)據(jù)同步,應(yīng)用于狀態(tài)數(shù)據(jù)在多個層級之間傳遞的場景。不同于 @Prop和 @Link,@Provide和 @Consume擺脫參數(shù)傳遞機制的束縛,實現(xiàn)跨層級傳遞。
4. @Observed裝飾器和 @ObjectLink裝飾器
對于多層嵌套的情況,比如二維數(shù)組,或者數(shù)組項class,或者class的屬性是class,他們的第二層的屬性變化是無法觀察到的。這就要用到 @Observed/@ObjectLink裝飾器
注意:@ObjectLink裝飾器不能在 @Entry裝飾的自定義組件中使用且 @ObjectLink 裝飾的變量不能被賦值,只能對其屬性進行賦值操作
7. 兄弟組件如何通信?
1. 通過公共父組件傳遞
如果兩個組件是同一個父組件的子組件,可以通過父組件來傳遞數(shù)據(jù)或事件。父組件可以作為中介,將一個子組件的數(shù)據(jù)或事件傳遞給另一個子組件。
2. 使用全局狀態(tài)管理
使用全局狀態(tài)管理(如 AppStorage、LocalStorage)來存儲共享數(shù)據(jù)。兄弟組件可以獨立地讀取和更新這個全局狀態(tài),從而實現(xiàn)通信。
8. 如何實現(xiàn)頁面間的通信?
1.使用?@Provide
和?@Consume
裝飾器(見6.3)
2.使用路由跳轉(zhuǎn)傳參
import { router } from '@kit.ArkUI';
router.pushUrl({url: 'pages/Detail', // 目標urlparams: paramsInfo // 添加params屬性,傳遞自定義參數(shù)})// 返回指定頁面并攜帶參數(shù)router.back({url: 'pages/Home',params: {info: '來自Home頁'}
});
3.使用導(dǎo)航跳轉(zhuǎn)傳參
this.pageStack.pushPath({ name: "PageOne", param: "PageOne Param" })
this.pageStack.pushPathByName("PageOne", "PageOne Param")
9. Navigation組件跳轉(zhuǎn)和router跳轉(zhuǎn)有什么區(qū)別?
官方文檔寫了很多,撿幾個我覺得比較重要的寫的
- Navigation:是路由容器組件,適用于模塊內(nèi)和跨模塊的路由切換,一次開發(fā),多端部署場景。Router位于頁面棧管理節(jié)點 stage 下面,不提供導(dǎo)航容器的概念。
- Navigation和 Router都支持跳轉(zhuǎn)傳參,但 Router對象中暫不支持方法變量。
- Navigation:支持清理指定路由,頁面棧沒有上限,可以無限跳轉(zhuǎn)。Router不支持清理指定路由且頁面棧最大為32,頁面棧到達32之后必須清除之后才能繼續(xù)跳轉(zhuǎn)。
- Navigation:支持自定義轉(zhuǎn)場動畫和共享元素轉(zhuǎn)場動畫。 Router:僅支持簡單自定義轉(zhuǎn)場動畫。
- Navigation:支持通過 setInterception 方法設(shè)置路由攔截。Router:不支持路由攔截。
- Navigation:支持沉浸式頁面和模態(tài)嵌套路由。Router:不支持,需要通過窗口配置實現(xiàn)沉浸式頁面。
總而言之,Navigation 組件在功能上更具豐富性和靈活性,特別是在處理復(fù)雜的導(dǎo)航結(jié)構(gòu)、動效和路由管理方面。
而 Router 則提供了更基礎(chǔ)的路由跳轉(zhuǎn)功能,適合簡單的路由需求。開發(fā)者可以根據(jù)應(yīng)用的具體需求和設(shè)計選擇最合適的路由方案。
具體的區(qū)別如下表:
10. HarmonyOS與Android和iOS有什么區(qū)別?
HarmonyOS 是華為開發(fā)的一個開源、分布式的操作系統(tǒng)。它設(shè)計用于多種設(shè)備,包括智能手機、平板電腦、智能電視和物聯(lián)網(wǎng)設(shè)備。與Android和iOS的主要區(qū)別在于:
- 分布式架構(gòu):HarmonyOS支持跨設(shè)備無縫協(xié)作,允許設(shè)備之間共享硬件資源。
- 性能:HarmonyOS優(yōu)化了任務(wù)調(diào)度和內(nèi)存管理,提高了性能和響應(yīng)速度。
- 安全性:HarmonyOS采用了多層次的安全策略,包括數(shù)據(jù)加密和安全啟動。
- 生態(tài)系統(tǒng):HarmonyOS正在構(gòu)建自己的應(yīng)用生態(tài)系統(tǒng),鼓勵開發(fā)者使用Ark Ts和ArkUI框架。
11. 什么是Ability?
Ability是應(yīng)用/服務(wù)所具備的能力的抽象,一個Module可以包含一個或多個 Ability ,在鴻蒙系統(tǒng)中,Ability提供了對 Ability生命周期、上下文環(huán)境等調(diào)用管理的能力,包括 Ability創(chuàng)建、銷毀、轉(zhuǎn)儲客戶端信息等
鴻蒙系統(tǒng)中的 Ability主要分為兩種類型:UIAbility和 ExtensionAbility。
1. UIAbility :
- 定義 :包含UI界面,提供展示UI的能力,主要用于和用戶交互 。
- 創(chuàng)建 :在模塊中添加UIAbility時,選中對應(yīng)的模塊,單擊鼠標右鍵,選擇New > Ability,設(shè)置Ability名稱,選擇是否在設(shè)備主屏幕上顯示該功能的啟動圖標,單擊Finish完成Ability創(chuàng)建 。
2. ExtensionAbility :
- 定義 :提供特定場景的擴展能力,滿足更多的使用場景 。
- 創(chuàng)建 :在模塊中添加ExtensionAbility時,選中對應(yīng)的模塊,單擊鼠標右鍵,選擇不同的場景類型(如Accessibility、EmbeddedUIExtensionAbility等) 。當前僅Application工程支持創(chuàng)建ExtensionAbility。設(shè)置Ability名稱,單擊Finish完成ExtensionAbility創(chuàng)建。
此外,Ability是Ability模塊的基類,提供系統(tǒng)配置更新回調(diào)和系統(tǒng)內(nèi)存調(diào)整回調(diào) 。Ability的繼承關(guān)系包括UIAbility和ExtensionAbility等具體類.
總之,Ability是鴻蒙系統(tǒng)中用于管理應(yīng)用能力的核心組件,通過不同類型的Ability可以實現(xiàn)不同的功能需求。
12. ArkUI框架有哪些特點?
ArkUI框架是鴻蒙(HarmonyOS)中的一個重要組件框架,具有以下幾個特點:
- 組件樹結(jié)構(gòu) : ArkUI框架通過布局組件和基礎(chǔ)組件構(gòu)建界面描述樹(組件樹),其中基礎(chǔ)組件為葉子節(jié)點,布局組件為中間節(jié)點 。當用戶進行交互時,會觸發(fā)界面修改,通過重新渲染組件樹來實現(xiàn)應(yīng)用界面更新 。
- 數(shù)據(jù)與UI更新過程 : ArkUI框架的數(shù)據(jù)處理過程和UI更新過程是分開進行的。數(shù)據(jù)處理過程中,主要是對狀態(tài)數(shù)據(jù)進行更新,并通過標臟過程確定布局最小影響范圍,減少不必要的重新布局 。UI更新過程包括組件標臟、布局、測量和渲染等階段 。
- 布局組件 : ArkUI框架提供了多種布局組件,如Row、Column、Stack、Flex、List、Grid、RelativeContainer等。開發(fā)者可以根據(jù)場景選擇合適的布局組件,以優(yōu)化性能 。例如,線性布局(Row、Column)適用于橫向或縱向排列組件,而彈性布局(Flex)適用于需要彈性排列的場景。
- 性能優(yōu)化 : ArkUI框架在性能優(yōu)化方面做了很多工作。例如,通過減少不必要的組件嵌套和節(jié)點數(shù)量,降低布局測算的復(fù)雜度,從而提升性能。開發(fā)者可以使用DevEco Studio提供的工具(如Profiler和ArkUI Inspector)來查看性能瓶頸和組件樹結(jié)構(gòu),進一步優(yōu)化應(yīng)用性能。
- 狀態(tài)管理 : ArkUI框架支持狀態(tài)管理最佳實踐,通過有效的狀態(tài)管理減少無效的UI更新操作,提升性能。例如,在狀態(tài)變量變化導(dǎo)致UI更新時,只更新部分組件,而不是重新渲染整個界面。
13. 跨設(shè)備通信的方式有哪些?
HarmonyOS支持多種跨設(shè)備通信方式,包括:
- 分布式軟總線:一種高性能的通信機制,允許設(shè)備之間建立直接連接,進行數(shù)據(jù)傳輸。
- 藍牙:使用標準的藍牙技術(shù)進行設(shè)備間的通信。
- WLAN:通過WLAN網(wǎng)絡(luò)實現(xiàn)設(shè)備間的通信。
- 遠程服務(wù)調(diào)用:通過分布式任務(wù)調(diào)度實現(xiàn)跨設(shè)備的服務(wù)調(diào)用。
14. 如何實現(xiàn)應(yīng)用的后臺運行?
- 后臺服務(wù):使用后臺服務(wù)(如BackgroundService)來執(zhí)行不需要用戶直接交互的任務(wù)。
- 定時任務(wù):通過系統(tǒng)提供的定時任務(wù)機制(如AlarmService)來周期性執(zhí)行后臺任務(wù)。
- 事件監(jiān)聽:注冊系統(tǒng)事件,如網(wǎng)絡(luò)變化、電量變化等,以在特定事件發(fā)生時喚醒應(yīng)用進行處理。
15. Ability是如何與用戶交互的?
- 界面顯示:Ability可以包含一個或多個AbilitySlice,用于顯示UI界面并與用戶進行交互。
- 事件處理:Ability可以處理用戶的輸入事件,如觸摸、按鍵等。
- 數(shù)據(jù)綁定:Ability可以使用數(shù)據(jù)綁定機制,將UI組件與數(shù)據(jù)模型綁定,實現(xiàn)數(shù)據(jù)的自動更新和交互。
- 通知:Ability可以通過系統(tǒng)通知機制向用戶發(fā)送通知,即使應(yīng)用不在前臺運行。
16. 如何實現(xiàn)應(yīng)用的多語言支持?
- 資源文件:為每種語言創(chuàng)建資源文件(如string.json),并在里面定義所有可本地化的字符串。
- 資源引用:在代碼中使用資源ID引用字符串,而不是硬編碼文本。
- 系統(tǒng)設(shè)置:應(yīng)用會自動根據(jù)系統(tǒng)設(shè)置的語言環(huán)境加載相應(yīng)的資源文件。
- 動態(tài)切換:支持在應(yīng)用運行時切換語言,并動態(tài)更新UI。
17. 分布式數(shù)據(jù)庫是如何實現(xiàn)數(shù)據(jù)同步的?
- 分布式事務(wù):確保跨設(shè)備的數(shù)據(jù)庫操作具有原子性、一致性、隔離性和持久性。
- 數(shù)據(jù)版本控制:為數(shù)據(jù)添加版本號,確保同步時數(shù)據(jù)的一致性。
- 沖突解決策略:定義沖突解決策略,處理并發(fā)操作導(dǎo)致的數(shù)據(jù)沖突。
- 網(wǎng)絡(luò)狀態(tài)感知:根據(jù)網(wǎng)絡(luò)狀態(tài)智能同步數(shù)據(jù),優(yōu)化同步效率和流量使用。
18. 如何優(yōu)化應(yīng)用的性能?
- 內(nèi)存管理:合理分配和釋放內(nèi)存,避免內(nèi)存泄漏。
- 后臺優(yōu)化:合理使用后臺服務(wù)和定時任務(wù),避免不必要的后臺運行。
- UI渲染優(yōu)化:使用輕量級的UI組件,減少布局復(fù)雜度,優(yōu)化渲染性能。
- 資源優(yōu)化:壓縮圖片和媒體資源,減少應(yīng)用的體積和加載時間。
19. HarmonyOS中的權(quán)限管理模型是怎樣的?
- 權(quán)限聲明:應(yīng)用在config.json中聲明所需的權(quán)限。
- 權(quán)限申請:在應(yīng)用運行時,根據(jù)需要動態(tài)申請權(quán)限。
- 權(quán)限檢查:在執(zhí)行敏感操作前,檢查是否已獲得相應(yīng)權(quán)限。
- 權(quán)限分組:系統(tǒng)將權(quán)限分為不同的組,便于管理和申請。
20. LazyForEach是什么?
LazyForEach 是一個用于高效渲染列表的組件或功能,它允許開發(fā)者在用戶滾動列表時才加載和渲染列表項,而不是一次性渲染整個列表。這種按需渲染的方式可以顯著提高應(yīng)用的性能,特別是在處理大量數(shù)據(jù)時。
21. LazyForEach的工作原理是什么?
LazyForEach 的工作原理通常是基于用戶的滾動位置來動態(tài)地創(chuàng)建和銷毀列表項的組件實例。當用戶滾動到列表的某個部分時,LazyForEach 會加載并渲染那些即將進入視圖的列表項,同時可能會卸載那些滾出視圖的列表項,以節(jié)省內(nèi)存和計算資源。
22. Router.replace()方法的作用是什么?和Router.pushUrl()方法有什么區(qū)別?
Router.replace()方法用于替換當前路由,并將目標路由壓入棧頂。與Router.pushUrl()方法不同,Router.replace()方法不會保留當前路由,而是直接替換掉當前路由。
23. 如何實現(xiàn)應(yīng)用的沉浸式模式?
沉浸式模式是指應(yīng)用界面呈現(xiàn)出沉浸式的全屏模式,不留任何系統(tǒng)UI,用戶只能看到應(yīng)用內(nèi)容。在沉浸式模式下,應(yīng)用的UI元素會被覆蓋,但系統(tǒng)狀態(tài)欄、導(dǎo)航欄、鍵盤等系統(tǒng)UI依然可見。以下是實現(xiàn)步驟
1. 設(shè)置窗口屬性:
在應(yīng)用的入口Ability中,可以通過設(shè)置窗口屬性來實現(xiàn)沉浸式模式。這通常涉及到配置窗口特性(Window Features)來隱藏狀態(tài)欄和導(dǎo)航欄。
2. 使用系統(tǒng)API:
鴻蒙OS提供了API來控制系統(tǒng)UI的顯示和隱藏。你可以在應(yīng)用的代碼中調(diào)用這些API來實現(xiàn)沉浸式效果。
3. 配置應(yīng)用的配置文件:
在應(yīng)用的config.json或其他配置文件中,可以聲明應(yīng)用需要的窗口特性,如ohos:immersive。
4. 動態(tài)切換:
應(yīng)用可以根據(jù)用戶的交互或特定場景動態(tài)地進入或退出沉浸式模式。這可能涉及到監(jiān)聽用戶的手勢或其他事件來切換UI狀態(tài)。
5. 適配不同設(shè)備:
不同的設(shè)備可能有不同的屏幕和系統(tǒng)UI,因此在實現(xiàn)沉浸式模式時,需要考慮不同設(shè)備的適配問題。
24. 如何獲取屏幕的安全區(qū)域?
- 可以通過設(shè)置組件的expandSafeArea屬性來獲取獲取UIWindow:首先,你需要獲取到當前頁面的UIWindow實例。
- 調(diào)用getSafeArea方法:通過UIWindow實例調(diào)用getSafeArea方法來獲取安全區(qū)域的Rect對象。
示例:
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 {@Overridepublic void onStart(Intent intent) {super.onStart(intent);setUIContent(new SurfaceLayout(this));UIWindow window = getUIWindow();if (window != null) {// 獲取安全區(qū)域Rect safeArea = window.getSafeArea();// 在這里可以使用safeArea對象,它包含了安全區(qū)域的位置和尺寸信息// 例如,可以使用safeArea.left, safeArea.top, safeArea.right, safeArea.bottom}}
}
25. ArkTs是什么?
ArkTs介紹
ArkTS是HarmonyOS優(yōu)選的主力應(yīng)用開發(fā)語言。保持了TypeScript的基本風(fēng)格,同時通過規(guī)范定義強化開發(fā)期靜態(tài)檢查和分析,提升程序執(zhí)行穩(wěn)定性和性能。
ArkTS的主要特點包括:
- 靜態(tài)類型檢查:ArkTS在編譯時進行類型檢查,這有助于在代碼運行前發(fā)現(xiàn)和修復(fù)錯誤,提高代碼的穩(wěn)定性和性能。
- 聲明式UI:ArkTS定義了聲明式UI描述,允許開發(fā)者以更簡潔、更自然的方式開發(fā)跨端應(yīng)用。
- 狀態(tài)管理:ArkTS提供了多維度的狀態(tài)管理機制,使得與UI相關(guān)聯(lián)的數(shù)據(jù)可以在組件內(nèi)使用,也可以在不同組件層級間傳遞,支持單向和雙向數(shù)據(jù)流。
- 渲染控制:ArkTS支持條件渲染、循環(huán)渲染和數(shù)據(jù)懶加載,允許開發(fā)者根據(jù)應(yīng)用的不同狀態(tài)渲染UI內(nèi)容。
- 兼容性:ArkTS兼容TS/JavaScript生態(tài),開發(fā)者可以使用TS/JS進行開發(fā)或復(fù)用已有代碼。
- 并發(fā)機制:ArkTS支持輕量化的并發(fā)機制,允許開發(fā)者編寫并發(fā)代碼,提高應(yīng)用的性能和響應(yīng)速度。
26. ArkTs與TypeScript有什么區(qū)別?(答5點以上)
ArkTs官方文檔
ArkTS 是基于 TypeScript 開發(fā)的框架,但是有一些限制和差異。ArkTS 旨在提供更嚴格的類型檢查和優(yōu)化的代碼性能,同時確保與 HarmonyOS 的開發(fā)環(huán)境和特性兼容。以下是 ArkTS 與 TypeScript 的差異:
- 不支持使用對象字面量聲明類型。
- 不支持使用 var關(guān)鍵字。
- 不支持使用 in運算符。
- 不支持導(dǎo)入斷言。
- 不支持使用 any類型。
- 不支持使用 import賦值表達式。
- 不支持使用 require導(dǎo)入
具體區(qū)別:
- 生成器函數(shù):ArkTS 不支持 TypeScript 中的生成器函數(shù)(使用 function* 定義的函數(shù)),應(yīng)使用 async 或 await 機制進行并行任務(wù)處理 。
- 參數(shù)解構(gòu):在函數(shù)參數(shù)中使用解構(gòu)賦值是 TypeScript 的特性,ArkTS 不支持參數(shù)解構(gòu),需要顯式傳遞參數(shù) 。
- 函數(shù)內(nèi)聲明函數(shù):TypeScript 允許在函數(shù)內(nèi)部聲明新的函數(shù),而 ArkTS 不支持在函數(shù)內(nèi)聲明函數(shù),應(yīng)使用 lambda 函數(shù)代替 。
- new.target:ArkTS 不支持 new.target 元屬性,這是 TypeScript 中用于反射的屬性 。
- 確定賦值斷言:TypeScript 中的 ! 確定賦值斷言在 ArkTS 中不被支持,應(yīng)初始化變量或使用其他方式確保賦值 。
- 原型上的賦值:ArkTS 不支持在對象的原型上進行賦值,這與 TypeScript 不同 。
- globalThis:ArkTS 不支持 globalThis,這是 TypeScript 中用于獲取全局對象的屬性 。
- Function.prototype.apply、Function.prototype.call 和 Function.prototype.bind:ArkTS 不支持這些函數(shù),它們在 TypeScript 中用于控制函數(shù)的 this 綁定 。
- instanceof 和 as 類型保護:ArkTS 不支持 is 運算符,必須使用 instanceof 運算符替代,并且在使用之前,必須使用 as 運算符將對象轉(zhuǎn)換為需要的類型 。
- 接口繼承類:在 TypeScript 中,接口可以繼承類,但在 ArkTS 中,接口只能繼承接口 。
- 構(gòu)造函數(shù)類型:ArkTS 不支持使用構(gòu)造函數(shù)類型,應(yīng)改用 lambda 函數(shù) 。
- enum 聲明合并:ArkTS 不支持 enum 聲明合并,所有相關(guān)的枚舉成員必須在同一個聲明中 。
- 命名空間作為對象:ArkTS 不支持將命名空間用作對象,可以使用類或模塊替代 。
- 非聲明語句在命名空間中:ArkTS 中,命名空間用于定義標志符可見范圍,不支持命名空間中的非聲明語句 。
- import default as ...:ArkTS 不支持 import default as ... 語法,應(yīng)使用顯式的 import ... from ... 語法 。
- require 和 import 賦值表達式:ArkTS 不支持通過 require 導(dǎo)入,也不支持 import 賦值表達式,應(yīng)使用 import 語法 。
- ambient 模塊聲明:ArkTS 不支持 declare module 語法,應(yīng)直接導(dǎo)入需要的內(nèi)容 。
- new.target:ArkTS 不支持 new.target 元屬性,這是 TypeScript 中用于反射的屬性 。
- Function.prototype.apply、Function.prototype.call 和 Function.prototype.bind:ArkTS 不支持這些函數(shù),它們在 TypeScript 中用于控制函數(shù)的 this 綁定 。
- as const 斷言:ArkTS 不支持 as const 斷言,這是 TypeScript 中用于標注字面量的相應(yīng)字面量類型的語法 。
- any:ArkTS 不支持any類型, 應(yīng)使用更具體的類型替代 。
27. @Provider和@Consumer vs @Provide和@Consume的區(qū)別?
@Provider和@Consumer 官方文檔
28. @Prop和@ObjectLink裝飾器有什么區(qū)別?
1.用途
- @Prop裝飾器:主要用于在組件之間傳遞數(shù)據(jù),將父組件的值傳遞給子組件。它定義了子組件的屬性,可以接收來自父組件的賦值。@ObjectLink用于建立對象之間的鏈接,通常用于在組件內(nèi)部或組件之間共享和同步狀態(tài)。它可以將一個對象的屬性與另一個對象的屬性進行鏈接,當一個對象的屬性發(fā)生變化時,另一個對象的屬性也會自動更新。
2. 數(shù)據(jù)傳遞方式
- @Prop:是單向的數(shù)據(jù)傳遞,從父組件到子組件。父組件可以設(shè)置子組件的 @Prop屬性值,但子組件不能直接修改這個值。@ObjectLink是雙向的數(shù)據(jù)傳遞,父組件和子組件都可以修改子組件的 @ObjectLink屬性值。
3. 性能
- @Prop會深拷貝數(shù)據(jù),具有拷貝的性能開銷,性能低于 @ObjectLink詳見官方文檔。
29. ForEach和LazyForEach的區(qū)別?
ForEach和LazyForEach都是用于渲染列表的裝飾器,它們的區(qū)別在于:
- ForEach:渲染列表時,會將列表中的每一項都渲染一次,適用于列表項數(shù)量較少的情況。
- LazyForEach:渲染列表時,只渲染當前可見的列表項,適用于列表項數(shù)量較多的情況。
30. UIAbility的生命周期有哪些?
官方文檔說明
UIAbility的生命周期包括Create、Foreground、Background、Destroy四個狀態(tài)
31. H5如何與HarmonyOS應(yīng)用(webView)進行通信?官方文檔
- 應(yīng)用側(cè)調(diào)用前端頁面JS函數(shù)
應(yīng)用側(cè)可以通過runJavaScript()方法異步調(diào)用前端頁面的JavaScript相關(guān)函數(shù),并通過Promise方式返回腳本執(zhí)行的結(jié)果。runJavaScript需要在loadUrl完成后,比如onPageEnd中調(diào)用。
- 前端頁面調(diào)用應(yīng)用側(cè)函數(shù)
使用Web組件將應(yīng)用側(cè)代碼注冊到前端頁面中,注冊完成之后,前端頁面中使用注冊的對象名稱就可以調(diào)用應(yīng)用側(cè)的函數(shù),實現(xiàn)在前端頁面中調(diào)用應(yīng)用側(cè)方法。注冊應(yīng)用側(cè)代碼有兩種方式,一種在Web組件初始化調(diào)用,使用javaScriptProxy()接口。另外一種在Web組件初始化完成后調(diào)用,使用registerJavaScriptProxy()接口。
32. 如何實現(xiàn)圖片上傳?
有兩種方式原生和Web組件:
- 原生:使用上傳下載模塊(ohos.request)的上傳接口將本地文件(圖片)上傳,需聲明權(quán)限:ohos.permission.INTERNET。
代碼示例:
// pages/xxx.ets
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import { BusinessError, request } from '@kit.BasicServicesKit';// 獲取應(yīng)用文件路徑
let context = getContext(this) as common.UIAbilityContext;
let cacheDir = context.cacheDir;// 新建一個本地應(yīng)用文件
let file = fs.openSync(cacheDir + '/test.txt', fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.writeSync(file.fd, 'upload file test');
fs.closeSync(file);// 上傳任務(wù)配置項
let header = new Map<Object, string>();
header.set('key1', 'value1');
header.set('key2', 'value2');
let files: Array<request.File> = [
//uri前綴internal://cache 對應(yīng)cacheDir目錄{ filename: 'test.txt', name: 'test', uri: 'internal://cache/test.txt', type: 'txt' }
]
let data: Array<request.RequestData> = [{ name: 'name', value: 'value' }];
let uploadConfig: request.UploadConfig = {url: 'https://xxx',header: header,method: 'POST',files: files,data: data
}// 將本地應(yīng)用文件上傳至網(wǎng)絡(luò)服務(wù)器
try {request.uploadFile(context, uploadConfig).then((uploadTask: request.UploadTask) => {uploadTask.on('complete', (taskStates: Array<request.TaskState>) => {for (let i = 0; i < taskStates.length; i++) {console.info(`upload complete taskState: ${JSON.stringify(taskStates[i])}`);}});}).catch((err: BusinessError) => {console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);})
} catch (error) {let err: BusinessError = error as BusinessError;console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
}
- 使用axios上傳:使用axios上傳文件,需安裝axios依賴。
注意事項
- 上傳文件需要單獨導(dǎo)入FormData模塊
- 當前版本只支持 Stage 模型
- 上傳類型支持uri和ArrayBuffer,uri支持“internal”協(xié)議類型和沙箱路徑,僅支持"internal"協(xié)議類型,"internal://cache/"為必填字段,示例: internal://cache/path/to/file.txt;沙箱路徑示例:cacheDir + ‘/hello.txt’
- 請求的表單數(shù)據(jù)值為string類型
- 支持設(shè)置多部分表單數(shù)據(jù)的數(shù)據(jù)名稱和數(shù)據(jù)類型類型
- 上傳參數(shù)context:當uri為沙箱路徑,無需傳參context;若uri為“internal”協(xié)議類型,必須傳參context
當上傳的內(nèi)容為ArrayBuffer時,用法如下
import axios from '@ohos/axios'
import { FormData } from '@ohos/axios'
import fs from '@ohos.file.fs';// ArrayBuffer
let formData = new FormData()
let cacheDir = getContext(this).cacheDir
try {// 寫入let path = cacheDir + '/hello.txt';let file = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)fs.writeSync(file.fd, "hello, world"); // 以同步方法將數(shù)據(jù)寫入文件fs.fsyncSync(file.fd); // 以同步方法同步文件數(shù)據(jù)。fs.closeSync(file.fd);// 讀取let file2 = fs.openSync(path, 0o2);let stat = fs.lstatSync(path);let buf2 = new ArrayBuffer(stat.size);fs.readSync(file2.fd, buf2); // 以同步方法從流文件讀取數(shù)據(jù)。fs.fsyncSync(file2.fd);fs.closeSync(file2.fd);formData.append('file', buf2);// formData.append('file', buf2, { filename: 'text.txt', type: 'text/plain'}); 設(shè)置多部分表單數(shù)據(jù)的數(shù)據(jù)名稱和數(shù)據(jù)類型類型
} catch (err) {console.info('err:' + JSON.stringify(err));
}
// 發(fā)送請求
axios.post<string, AxiosResponse<string>, FormData>(this.uploadUrl, formData, {headers: { 'Content-Type': 'multipart/form-data' },context: getContext(this),onUploadProgress: (progressEvent: AxiosProgressEvent): void => {console.info(progressEvent && progressEvent.loaded && progressEvent.total ? Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%');
},
}).then((res: AxiosResponse) => {console.info("result" + JSON.stringify(res.data));
}).catch((error: AxiosError) => {console.error("error:" + JSON.stringify(error));
})
當上傳的uri時,用法如下
import axios from '@ohos/axios'
import { FormData } from '@ohos/axios'let formData = new FormData()
formData.append('file', 'internal://cache/blue.jpg')
// formData.append('file', cacheDir + '/hello.txt'); uri支持傳入沙箱路徑// 發(fā)送請求
axios.post<string, AxiosResponse<string>, FormData>('https://www.xxx.com/upload', formData, {headers: { 'Content-Type': 'multipart/form-data' },context: getContext(this),onUploadProgress: (progressEvent: AxiosProgressEvent): void => {console.info(progressEvent && progressEvent.loaded && progressEvent.total ? Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%');},
}).then((res: AxiosResponse<string>) => {console.info("result" + JSON.stringify(res.data));
}).catch((err: AxiosError) => {console.error("error:" + JSON.stringify(err));
})
33.hap、har、hsp三者的區(qū)別?
- HAP(Harmony Ability Package)是應(yīng)用安裝和運行的基本單元。HAP包是由代碼、資源、第三方庫、配置文件等打包生成的模塊包,其主要分為兩種類型:entry和feature。(又稱ability)
- HAR(Harmony Archive)是靜態(tài)共享包,可以包含代碼、C++庫、資源和配置文件。通過HAR可以實現(xiàn)多個模塊或多個工程共享ArkUI組件、資源等相關(guān)代碼。(又稱static library, 靜態(tài)共享包)
- HSP(Harmony Shared Package)是動態(tài)共享包,可以包含代碼、C++庫、資源和配置文件,通過HSP可以實現(xiàn)代碼和資源的共享。HSP不支持獨立發(fā)布,而是跟隨其宿主應(yīng)用的APP包一起發(fā)布,與宿主應(yīng)用同進程,具有相同的包名和生命周期。(又稱shared library, 動態(tài)共享包)
34. 鴻蒙常用的裝飾器有哪些?
- @State 定義狀態(tài),當前組件能使用
- @Prop 父子組件通信(特點:子組件數(shù)據(jù)不能修改)
- @Link 父子組件通信(特點:子組件數(shù)據(jù)可以修改)
- @Observed 和 @ObjectLink 父子組件通信(特點:嵌套第二層數(shù)據(jù)修改可以達到響應(yīng)式,之前方案不行)
- @Provide 和 @Consume 祖孫組件通信
- @Builder 和 @BuilderParam 父子組件通信,通信組件數(shù)據(jù)
- @Watch 監(jiān)視數(shù)據(jù)的變化(第一次不會觸發(fā))
35. 如何啟動一個 ability?
通過 context 對象的 startAbility 方法官方文檔:
import { common, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';context = getContext(this) as common.UIAbilityContext; // UIAbilityContextconst want: Want = {deviceId: '', // deviceId為空表示本設(shè)備bundleName: 'com.example.system', // AppScope/app.json5 中找abilityName: 'SecondAbility', // 去對應(yīng)的ability內(nèi)部找module.json5// moduleName: 'entry' // moduleName非必選parameters: { // 攜帶參數(shù)}
};
this.context.startAbility(want, (err: BusinessError) => {if (err.code) {// 顯式拉起Ability,通過bundleName、abilityName和moduleName可以唯一確定一個Abilityconsole.error(`Failed to startAbility. Code: ${err.code}, message: ${err.message}`);}
});
36. 顯示 want 和 隱式 want 的區(qū)別?
官方文檔
- 顯式Want:在啟動目標應(yīng)用組件時,調(diào)用方傳入的want參數(shù)中指定了abilityName和bundleName,稱為顯式Want。顯式Want通常用于應(yīng)用內(nèi)組件啟動,通過在Want對象內(nèi)指定本應(yīng)用Bundle名稱信息(bundleName)和abilityName來啟動應(yīng)用內(nèi)目標組件。當有明確處理請求的對象時,顯式Want是一種簡單有效的啟動目標應(yīng)用組件的方式。例如:打開其他窗口
- 隱式Want:在啟動目標應(yīng)用組件時,調(diào)用方傳入的want參數(shù)中未指定abilityName,稱為隱式Want。當需要處理的對象不明確時,可以使用隱式Want,在當前應(yīng)用中使用其他應(yīng)用提供的某個能力,而不關(guān)心提供該能力的具體應(yīng)用。隱式Want使用skills標簽來定義需要使用的能力,并由系統(tǒng)匹配聲明支持該請求的所有應(yīng)用來處理請求。例如,需要打開一個鏈接的請求,系統(tǒng)將匹配所有聲明支持該請求的應(yīng)用,然后讓用戶選擇使用哪個應(yīng)用打開鏈接。例如:將pdf文件傳遞給其他應(yīng)用窗口
總的來說
- 顯示want和隱式want的區(qū)別在于有無abilityName。有就是顯示want,沒有就是隱式want
- 顯示want主要用于當前應(yīng)用窗口跳轉(zhuǎn),隱式want打開其他應(yīng)用的窗口
37. 三層架構(gòu)是什么?
官方文檔
三層架構(gòu)為了“一次開發(fā),多端部署”,項目結(jié)構(gòu)采用三層架構(gòu)
三層工程結(jié)構(gòu)如下:
- commons(公共能力層):用于存放公共基礎(chǔ)能力集合(如工具庫、公共配置等)。commons層可編譯成一個或多個HAR包或HSP包,只可以被products和features依賴,不可以反向依賴。
- features(基礎(chǔ)特性層):開發(fā)頁面、組件(HAR包或HSP包)。
- products(產(chǎn)品定制層):定義phone\pad兩個ability,引用 features 的包和 commons 的包完成應(yīng)用功能
38. 優(yōu)化內(nèi)存有哪些方法?
官方文檔
1. 使用onMemoryLevel監(jiān)聽內(nèi)存變化
2. 使用LRUCache優(yōu)化ArkTS內(nèi)存
例如:我們搜索租房列表可以無限加載租房數(shù)據(jù),這樣數(shù)據(jù)會越來越多,我們使用LRUCacheUtil來管理數(shù)據(jù)
3. 使用生命周期管理優(yōu)化ArkTS內(nèi)存
例如:aboutToDisappear中銷毀訂閱事件,清除定時器等
4.使用purgeable優(yōu)化C++內(nèi)存
39. 多線程實現(xiàn)方式TaskPoll和Worker的區(qū)別?
- TaskPool和Worker均支持多線程并發(fā)能力。由于TaskPool的工作線程會綁定系統(tǒng)的調(diào)度優(yōu)先級,并且支持負載均衡(自動擴縮容),而Worker需要開發(fā)者自行創(chuàng)建,存在創(chuàng)建耗時以及不支持設(shè)置調(diào)度優(yōu)先級,故在性能方面使用TaskPool會優(yōu)于Worker,因此大多數(shù)場景推薦使用TaskPool。
- TaskPool偏向獨立任務(wù)維度,該任務(wù)在線程中執(zhí)行,無需關(guān)注線程的生命周期,超長任務(wù)(大于3分鐘且非長時任務(wù))會被系統(tǒng)自動回收;而Worker偏向線程的維度,支持長時間占據(jù)線程執(zhí)行,需要主動管理線程生命周期。
40. 音視頻的組件的使用方式?
- 視頻組件 Video
controller: VideoController = new VideoController()
Video({src: $rawfile('test.mp4'),previewUri: $r('app.media.startIcon'),controller: this.controller
})
.width('100%')
.height(200)
.autoPlay(true)
.controls(true)
- 音頻組件 Audio?官方文檔(了解)
//配置音頻渲染參數(shù)并創(chuàng)建AudioRenderer實例,音頻渲染參數(shù)的詳細信息可以查看AudioRendererOptions。
import { audio } from '@kit.AudioKit';
let audioStreamInfo: audio.AudioStreamInfo = {samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采樣率channels: audio.AudioChannel.CHANNEL_2, // 通道sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采樣格式encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 編碼格式
};
let audioRendererInfo: audio.AudioRendererInfo = {usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION,rendererFlags: 0
};
let audioRendererOptions: audio.AudioRendererOptions = {streamInfo: audioStreamInfo,rendererInfo: audioRendererInfo
};
audio.createAudioRenderer(audioRendererOptions, (err, data) => {if (err) {console.error(`Invoke createAudioRenderer failed, code is ${err.code}, message is ${err.message}`);return;} else {console.info('Invoke createAudioRenderer succeeded.');let audioRenderer = data;}
});
// 調(diào)用on('writeData')方法,訂閱監(jiān)聽音頻數(shù)據(jù)寫入回調(diào)。
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';
let bufferSize: number = 0;
class Options {offset?: number;length?: number;
}
let path = getContext().cacheDir;
//確保該路徑下存在該資源
let filePath = path + '/StarWars10s-2C-48000-4SW.wav';
let file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY);
let writeDataCallback = (buffer: ArrayBuffer) => {let options: Options = {offset: bufferSize,length: buffer.byteLength}fileIo.readSync(file.fd, buffer, options);bufferSize += buffer.byteLength;
}
audioRenderer.on('writeData', writeDataCallback);
//調(diào)用start()方法進入running狀態(tài),開始渲染音頻。
import { BusinessError } from '@kit.BasicServicesKit';
audioRenderer.start((err: BusinessError) => {if (err) {console.error(`Renderer start failed, code is ${err.code}, message is ${err.message}`);} else {console.info('Renderer start success.');}
});
//調(diào)用stop()方法停止渲染。
import { BusinessError } from '@kit.BasicServicesKit';
audioRenderer.stop((err: BusinessError) => {if (err) {console.error(`Renderer stop failed, code is ${err.code}, message is ${err.message}`);} else {console.info('Renderer stopped.');}
});
// 調(diào)用release()方法銷毀實例,釋放資源。
import { BusinessError } from '@kit.BasicServicesKit';
audioRenderer.release((err: BusinessError) => {if (err) {console.error(`Renderer release failed, code is ${err.code}, message is ${err.message}`);} else {console.info('Renderer released.');}
});