移動應用用戶體驗
典型的 Android 應用包含多個應用組件,包括 Activity、Fragment、Service、內(nèi)容提供程序和(hé)廣播接收器。您需要(yào)在應用清單中聲明(míng)其中的大多數(shù)應用組件。Android 操作(zuò)系統随後會使用此文件來決定如(rú)何将您的應用集成到設備的整體用戶體驗中。鑒于典型的 Android 應用可(kě)能(néng)包含多個組件,并且用戶經常會在短時(shí)間(jiān)內(nèi)與多個應用進行(xíng)互動,因此應用需要(yào)适應不同類型的用戶驅動型工(gōng)作(zuò)流和(hé)任務。
請(qǐng)注意,移動設備的資源也很(hěn)有限,因此操作(zuò)系統可(kě)能(néng)随時(shí)終止某些應用進程以便為(wèi)新的進程騰出空間(jiān)。
鑒于這(zhè)種環境條件,您的應用組件可(kě)以不按順序地(dì)單獨啓動,并且操作(zuò)系統或用戶可(kě)以随時(shí)銷毀它們。由于這(zhè)些事件不受您的控制,因此您不應在內(nèi)存中存儲或保留任何應用數(shù)據或狀态,并且應用組件不應相互依賴。
常見(jiàn)的架構原則
如(rú)果您不應使用應用組件存儲應用數(shù)據和(hé)狀态,那(nà)麽您應該改為(wèi)如(rú)何設計應用呢?
随着 Android 應用大小不斷增加,您定義的架構務必要(yào)能(néng)允許應用擴縮、提升應用的穩健性并且方便對應用進行(xíng)測試。
應用架構定義了(le)應用的各個部分之間(jiān)的界限以及每個部分應承擔的職責。為(wèi)了(le)滿足上(shàng)述需求,您應該按照某些特定原則設計應用架構。
分離關注點
要(yào)遵循的最重要(yào)的原則是分離關注點。 一(yī)種常見(jiàn)的錯誤是在一(yī)個 Activity 或 Fragment 中編寫所有代碼。這(zhè)些基于界面的類應僅包含處理界面和(hé)操作(zuò)系統交互的邏輯。您應使這(zhè)些類盡可(kě)能(néng)保持精簡,這(zhè)樣可(kě)以避免許多與組件生命周期相關的問(wèn)題,并提高這(zhè)些類的可(kě)測試性。
請(qǐng)注意,您并非擁有 Activity 和(hé) Fragment 的實現;它們隻是表示 Android 操作(zuò)系統與應用之間(jiān)關系的粘合類。操作(zuò)系統可(kě)能(néng)會根據用戶互動或因內(nèi)存不足等系統條件随時(shí)銷毀它們。為(wèi)了(le)提供令人(rén)滿意的用戶體驗和(hé)更易于管理的應用維護體驗,最好盡量減少(shǎo)對它們的依賴。
通(tōng)過數(shù)據模型驅動界面
另一(yī)個重要(yào)原則是您應該通(tōng)過數(shù)據模型驅動界面(最好是持久性模型)。數(shù)據模型代表應用的數(shù)據。它們獨立于應用中的界面元素和(hé)其他(tā)組件。這(zhè)意味着它們與界面和(hé)應用組件的生命周期沒有關聯,但(dàn)仍會在操作(zuò)系統決定從(cóng)內(nèi)存中移除應用的進程時(shí)被銷毀。
持久性模型是理想之選,原因如(rú)下(xià):
如(rú)果 Android 操作(zuò)系統銷毀應用以釋放資源,用戶不會丢失數(shù)據。
當網絡連接不穩定或不可(kě)用時(shí),應用會繼續工(gōng)作(zuò)。
如(rú)果您的應用架構以數(shù)據模型類為(wèi)基礎,您的應用會更便于測試、更穩定可(kě)靠。
單一(yī)數(shù)據源
在應用中定義新數(shù)據類型時(shí),您應為(wèi)其分配單一(yī)數(shù)據源 (SSOT)。SSOT 是該數(shù)據的所有者,而且隻有此 SSOT 可(kě)以修改或轉變該數(shù)據。為(wèi)了(le)實現這(zhè)一(yī)點,SSOT 會以不可(kě)變類型公開(kāi)數(shù)據;而且為(wèi)了(le)修改數(shù)據,SSOT 會公開(kāi)函數(shù)或接收其他(tā)類型可(kě)以調用的事件。
此模式具有多種優勢:
将對特定類型數(shù)據的所有更改集中到一(yī)處。
保護數(shù)據,防止其他(tā)類型篡改此數(shù)據。
更易于跟蹤對數(shù)據的更改。因此,更容易發現 bug。
在離線優先應用中,應用數(shù)據的單一(yī)數(shù)據源通(tōng)常是數(shù)據庫。在其他(tā)某些情況下(xià),單一(yī)數(shù)據源可(kě)以是 ViewModel 甚至是界面。
單向數(shù)據流
在我們的指南中,單一(yī)數(shù)據源原則常常與單向數(shù)據流 (UDF) 模式一(yī)起使用。在 UDF 中,狀态僅朝一(yī)個方向流動。修改數(shù)據的事件朝相反方向流動。
在 Android 中,狀态或數(shù)據通(tōng)常從(cóng)分區(qū)層次結構中較高的分區(qū)類型流向較低(dī)的分區(qū)類型。事件通(tōng)常在分區(qū)層次結構中較低(dī)的分區(qū)類型觸發,直到其到達 SSOT 的相應數(shù)據類型。例如(rú),應用數(shù)據通(tōng)常從(cóng)數(shù)據源流向界面。用戶事件(例如(rú)按鈕按下(xià)操作(zuò))從(cóng)界面流向 SSOT,在 SSOT 中應用數(shù)據被修改并以不可(kě)變類型公開(kāi)。
此模式可(kě)以更好地(dì)保證數(shù)據一(yī)緻性,不易出錯、更易于調試,并且具備 SSOT 模式的所有優勢。
推薦的應用架構
本部分将演示如(rú)何按照建議(yì)的最佳做(zuò)法構建應用。
注意:本頁中提供的建議(yì)和(hé)最佳實踐可(kě)應用于各種應用。遵循這(zhè)些建議(yì)和(hé)最佳實踐可(kě)以提升應用的可(kě)擴展性、質量和(hé)穩健性,并可(kě)使應用更易于測試。不過,您應該将這(zhè)些提示視(shì)為(wèi)指南,并視(shì)需要(yào)進行(xíng)調整來滿足您的要(yào)求。
基于上(shàng)一(yī)部分提到的常見(jiàn)架構原則,每個應用應至少(shǎo)有兩個層:
界面層 - 在屏幕上(shàng)顯示應用數(shù)據。
數(shù)據層 - 包含應用的業務邏輯并公開(kāi)應用數(shù)據。
您可(kě)以額外(wài)添加一(yī)個名為(wèi)“網域層”的架構層,以簡化和(hé)重複使用界面層與數(shù)據層之間(jiān)的交互。
現代應用架構
此現代應用架構鼓勵采用以下(xià)方法及其他(tā)一(yī)些方法:
反應式分層架構。
應用的所有層中的單向數(shù)據流 (UDF)。
包含狀态容器的界面層,用于管理界面的複雜(zá)性。
協程和(hé)數(shù)據流。
依賴項注入最佳實踐。
如(rú)需了(le)解詳情,請(qǐng)參閱以下(xià)部分、目錄中的其他(tā)“架構”頁面以及包含最重要(yào)的最佳實踐摘要(yào)的“建議(yì)”頁面。
界面層
界面層(或呈現層)的作(zuò)用是在屏幕上(shàng)顯示應用數(shù)據。每當數(shù)據發生變化時(shí),無論是因為(wèi)用戶互動(例如(rú)按了(le)某個按鈕),還是因為(wèi)外(wài)部輸入(例如(rú)網絡響應),界面都(dōu)應随之更新,以反映這(zhè)些變化。
界面層由以下(xià)兩部分組成:
在屏幕上(shàng)呈現數(shù)據的界面元素。您可(kě)以使用 View 或 Jetpack Compose 函數(shù)構建這(zhè)些元素。
用于存儲數(shù)據、向界面提供數(shù)據以及處理邏輯的狀态容器(如(rú) ViewModel 類)。
數(shù)據層
應用的數(shù)據層包含業務邏輯。業務邏輯決定應用的價值,它包含決定應用如(rú)何創建、存儲和(hé)更改數(shù)據的規則。
數(shù)據層由多個存儲庫組成,其中每個存儲庫都(dōu)可(kě)以包含零到多個數(shù)據源。您應該為(wèi)應用中處理的每種不同類型的數(shù)據分别創建一(yī)個存儲庫類。例如(rú),您可(kě)以為(wèi)與電影相關的數(shù)據創建一(yī)個 MoviesRepository 類,或者為(wèi)與付款相關的數(shù)據創建一(yī)個 PaymentsRepository 類。
圖 3. 數(shù)據層在應用架構中的作(zuò)用。
存儲庫類負責以下(xià)任務:
向應用的其餘部分公開(kāi)數(shù)據。
集中處理數(shù)據變化。
解決多個數(shù)據源之間(jiān)的沖突。
對應用其餘部分的數(shù)據源進行(xíng)抽象化處理。
包含業務邏輯。
每個數(shù)據源類應僅負責處理一(yī)個數(shù)據源,數(shù)據源可(kě)以是文件、網絡來源或本地(dì)數(shù)據庫。數(shù)據源類是應用與數(shù)據操作(zuò)系統之間(jiān)的橋梁。
如(rú)需詳細了(le)解此層,請(qǐng)參閱數(shù)據層頁面。
網域層
網域層是位于界面與數(shù)據層之間(jiān)的可(kě)選層。
網域層負責封裝複雜(zá)的業務邏輯,或者由多個 ViewModel 重複使用的簡單業務邏輯。此層是可(kě)選的,因為(wèi)并非所有應用都(dōu)有這(zhè)類需求。請(qǐng)僅在需要(yào)時(shí)使用該層,例如(rú)處理複雜(zá)邏輯或支持可(kě)重用性。
此層中的類通(tōng)常稱為(wèi)“用例”或“交互方”。每個用例都(dōu)應僅負責單個功能(néng)。例如(rú),如(rú)果多個 ViewModel 依賴時(shí)區(qū)在屏幕上(shàng)顯示适當的消息,則您的應用可(kě)能(néng)具有 GetTimeZoneUseCase 類。
如(rú)需詳細了(le)解此層,請(qǐng)參閱網域層頁面。
管理組件之間(jiān)的依賴關系
應用中的類要(yào)依賴其他(tā)類才能(néng)正常工(gōng)作(zuò)。您可(kě)以使用以下(xià)任一(yī)設計模式來收集特定類的依賴項:
依賴注入 (DI):依賴注入使類能(néng)夠定義其依賴項而不構造它們。在運行(xíng)時(shí),另一(yī)個類負責提供這(zhè)些依賴項。
服務定位器:服務定位器模式提供了(le)一(yī)個注冊表,類可(kě)以從(cóng)中獲取其依賴項而不構造它們。
您可(kě)以借助這(zhè)些模式來擴展代碼,因為(wèi)它們可(kě)提供清晰的依賴項管理模式(無需複制代碼,也不會增添複雜(zá)性)。 此外(wài),您還可(kě)以借助這(zhè)些模式在測試和(hé)生産實現之間(jiān)快(kuài)速切換。
我們建議(yì)在 Android 應用中采用依賴項注入模式并使用 Hilt 庫。Hilt 通(tōng)過遍曆依賴項樹(shù)自(zì)動構造對象,為(wèi)依賴項提供編譯時(shí)保證,并為(wèi) Android 框架類創建依賴項容器。
常見(jiàn)的最佳實踐
編程是一(yī)個創造性的領域,構建 Android 應用也不例外(wài)。 無論是在多個 activity 或 fragment 之間(jiān)傳遞數(shù)據,檢索遠程數(shù)據并将其保留在本地(dì)以在離線模式下(xià)使用,還是複雜(zá)應用遇到的任何其他(tā)常見(jiàn)情況,解決問(wèn)題的方法都(dōu)會有很(hěn)多種。
雖然以下(xià)建議(yì)不是強制性的,但(dàn)在大多數(shù)情況下(xià),遵循這(zhè)些建議(yì)會使您的代碼庫更強大、可(kě)測試性更高且更易維護:
不要(yào)将數(shù)據存儲在應用組件中。
請(qǐng)避免将應用的入口點(如(rú) activity、Service 和(hé)廣播接收器)指定為(wèi)數(shù)據源。相反,您應隻将其與其他(tā)組件協調,以檢索與該入口點相關的數(shù)據子集。每個應用組件存在的時(shí)間(jiān)都(dōu)很(hěn)短暫,具體取決于用戶與其設備的交互情況以及系統當前的整體運行(xíng)狀況。
減少(shǎo)對 Android 類的依賴。
您的應用組件應該是唯一(yī)依賴于 Android 框架 SDK API(例如(rú) Context 或 Toast)的類。将應用中的其他(tā)類與這(zhè)些類分離開(kāi)來有助于改善可(kě)測試性,并減少(shǎo)應用中的耦合。
在應用的各個模塊之間(jiān)設定明(míng)确定義的職責界限。
例如(rú),請(qǐng)勿在代碼庫中将從(cóng)網絡加載數(shù)據的代碼散布到多個類或軟件包中。同樣,也不要(yào)将不相關的職責(如(rú)數(shù)據緩存和(hé)數(shù)據綁定)定義到同一(yī)個類中。遵循推薦的應用架構可(kě)以幫助您解決此問(wèn)題。
盡量少(shǎo)公開(kāi)每個模塊中的代碼。
例如(rú),請(qǐng)勿試圖創建從(cóng)模塊提供內(nèi)部實現細節的快(kuài)捷方式。短期內(nèi),您可(kě)能(néng)會省點時(shí)間(jiān),但(dàn)随着代碼庫的不斷發展,您可(kě)能(néng)會反複陷入技術(shù)上(shàng)的麻煩。
專注于應用的獨特核心,以使其從(cóng)其他(tā)應用中脫穎而出。
不要(yào)一(yī)次又一(yī)次地(dì)編寫相同的樣闆代碼,這(zhè)是在做(zuò)無用功。 相反,您應将時(shí)間(jiān)和(hé)精力集中放在能(néng)讓應用與衆不同的方面上(shàng),并讓 Jetpack 庫以及建議(yì)的其他(tā)庫處理重複的樣闆。
考慮如(rú)何使應用的每個部分可(kě)獨立測試。
例如(rú),如(rú)果使用明(míng)确定義的 API 從(cóng)網絡獲取數(shù)據,将會更容易測試在本地(dì)數(shù)據庫中保留該數(shù)據的模塊。如(rú)果您将這(zhè)兩個模塊的邏輯混放在一(yī)處,或将網絡代碼分散在整個代碼庫中,那(nà)麽即便能(néng)夠進行(xíng)有效測試,難度也會大很(hěn)多。
類型負責其并發政策。
如(rú)果某種類型正在執行(xíng)長(cháng)時(shí)間(jiān)運行(xíng)的阻塞工(gōng)作(zuò),則應負責将該計算移至正确的線程。該特定類型知道(dào)它正在執行(xíng)的計算類型及其應在哪個線程中執行(xíng)。類型應該具有主線程安全性,這(zhè)意味着,您可(kě)以安全地(dì)從(cóng)主線程調用這(zhè)些類型而不會阻塞。
保留盡可(kě)能(néng)多的相關數(shù)據和(hé)最新數(shù)據。
這(zhè)樣,即使用戶的設備處于離線模式,他(tā)們也可(kě)以使用您應用的功能(néng)。請(qǐng)記住,并非所有用戶都(dōu)能(néng)享受到穩定的高速連接 - 即使有時(shí)可(kě)以使用,在比較擁擠的地(dì)方網絡信号也可(kě)能(néng)不佳。
架構的優勢
在應用中實現良好的架構會為(wèi)項目和(hé)工(gōng)程團隊帶來諸多好處:
提高整個應用的可(kě)維護性、質量和(hé)穩健性。
允許應用擴縮。盡可(kě)能(néng)減少(shǎo)代碼沖突,使更多人(rén)和(hé)更多團隊可(kě)以為(wèi)同一(yī)代碼庫做(zuò)貢獻。
有助于新手上(shàng)手。架構能(néng)使您的項目保持一(yī)緻性,讓團隊中的新成員(yuán)可(kě)以快(kuài)速上(shàng)手,并在更短時(shí)間(jiān)內(nèi)提高效率。
更易于測試。良好的架構鼓勵使用更簡單的類型,這(zhè)些類型通(tōng)常更易于測試。
可(kě)以使用明(míng)确定義的流程有條理地(dì)調查 bug。
在架構方面的投入也會對您的用戶産生直接積極影響。用戶能(néng)從(cóng)更穩定的應用中獲益;同時(shí),由于工(gōng)程團隊效率提高,用戶還可(kě)以享受更多功能(néng)。但(dàn)是,架構也需要(yào)前期時(shí)間(jiān)投入。建議(yì)您閱讀這(zhè)些案例研究,了(le)解其他(tā)公司在應用中使用良好架構的成功案例,這(zhè)有助于您向所在公司解釋前期時(shí)間(jiān)投入的必要(yào)性。
網站建設開(kāi)發|APP設計開(kāi)發|小程序建設開(kāi)發