黃慧 李荊軒
(1.中國第一汽車股份有限公司研發(fā)總院,長春130013;2.一汽大眾汽車有限公司,長春130011)
車載娛樂系統(tǒng)中的操作系統(tǒng)主要包括WinCE、QNX、Linux、Android、鴻蒙OS和阿里OS。由于汽車制造企業(yè)在定制方面的需求日益增多,Android系統(tǒng)因其生態(tài)化、靈活性和受用戶歡迎的優(yōu)點(diǎn),在市場上占據(jù)越來越大的份額。隨著搭載Android系統(tǒng)的車載娛樂系統(tǒng)增多,對Android應(yīng)用程序訪問整車電子控制器件的需求也越來越多。車載娛樂系統(tǒng)的Android應(yīng)用程序需要能夠正確地發(fā)送控制指令給整車電子器件,并將其狀態(tài)反饋到界面上,因此需要研究一種高效的設(shè)計模式來實(shí)現(xiàn)這一目標(biāo)。因此,本文對車載娛樂系統(tǒng)中Android應(yīng)用程序的設(shè)計模式進(jìn)行了研究。
車載娛樂系統(tǒng)中使用Android應(yīng)用程序訪問CAN網(wǎng)絡(luò)與Android 終端應(yīng)用程序訪問HTTP 網(wǎng)絡(luò)有所不同。車載應(yīng)用程序的主要功能特點(diǎn)在于管理涉及控制器局域網(wǎng)絡(luò)的業(yè)務(wù)邏輯和用戶界面。與Android終端應(yīng)用程序相比,車載應(yīng)用程序發(fā)送和接收CAN網(wǎng)絡(luò)報文具有以下不同之處:
(1)請求CAN網(wǎng)絡(luò)得到反饋所需的時間比請求HTTP網(wǎng)絡(luò)更長,這是因為請求CAN網(wǎng)絡(luò)需要考慮對方電子控制單元(Electronic Control Unit,ECU)計算的時間。
(2)CAN網(wǎng)絡(luò)會定時反饋對方ECU的狀態(tài)。
(3)如果對方ECU 存在非預(yù)期錯誤,將會通過CAN網(wǎng)絡(luò)反饋無效值或保留值。
本文研究了適用于車載應(yīng)用的CAN 網(wǎng)絡(luò)應(yīng)用程序設(shè)計模式和方法,并探討了適用于車載應(yīng)用的HTTP網(wǎng)絡(luò)應(yīng)用程序設(shè)計模式和方法。本文以Java作為Android 系統(tǒng)的上層開發(fā)語言,并使用Java 代碼作為示例。
模型-視圖-控制器(Model-View-Controller,MVC)是一種常用的設(shè)計模式,用于組織和管理軟件應(yīng)用程序中的交互和數(shù)據(jù)流。MVC設(shè)計模式,如圖1所示[4]。
圖1 MVC設(shè)計模式邏輯[4]
Model代表數(shù)據(jù)模型,負(fù)責(zé)保存和管理數(shù)據(jù)。當(dāng)數(shù)據(jù)發(fā)生變化時,Model負(fù)責(zé)通知View更新界面顯示。
View代表用戶界面,接收用戶的請求并將其傳遞給Controller。View 主要負(fù)責(zé)與用戶進(jìn)行交互和展示數(shù)據(jù)。
Controller是控制器,負(fù)責(zé)處理業(yè)務(wù)邏輯。當(dāng)Controller對業(yè)務(wù)進(jìn)行處理后,會通知Model進(jìn)行數(shù)據(jù)更新。
(1)模塊職責(zé)劃分明確。主要劃分為Model、View和Controller模塊,有利于代碼維護(hù)。
(2)這種設(shè)計模式使得數(shù)據(jù)、界面和業(yè)務(wù)邏輯之間的耦合度降低,提高了代碼的可維護(hù)性和可擴(kuò)展性。
(1)在Android 開發(fā)中,通常將Activity 組件作為控制器(Controller)角色來執(zhí)行。然而,在實(shí)際業(yè)務(wù)應(yīng)用中,Activity也會控制一些涉及業(yè)務(wù)邏輯刷新的用戶界面(User Interface,UI)元素,例如進(jìn)度條等。這就導(dǎo)致部分View 和Controller 的功能合并在同一個類別中,使得Activity 的代碼逐漸膨脹。這種情況下,View和Controller 之間存在耦合,不符合模型設(shè)計的初衷,給維護(hù)帶來了困難。
(2)此外,View 和Model 之間也存在一定的交互邏輯,并沒有完全分離開來,導(dǎo)致View 和Model 之間也存在耦合。
(3)上述設(shè)計還僅僅實(shí)現(xiàn)了在車載應(yīng)用中給對方ECU發(fā)送指令,并默認(rèn)對方ECU能成功執(zhí)行并刷新界面。但實(shí)際上,對方ECU并不一定能成功執(zhí)行該指令,并且從CAN網(wǎng)絡(luò)接收到反饋的時間也相對較長。因此,在Controller中需要額外設(shè)計,以便在對方ECU執(zhí)行失敗或用戶頻繁發(fā)送指令導(dǎo)致對方ECU不斷返回反饋的情況下,能正確通知Model并相應(yīng)地更新View。這使原本已經(jīng)龐大的Controller復(fù)雜度和大小進(jìn)一步增加。
(1)MVC 不適合用于處理與CAN 網(wǎng)絡(luò)相關(guān)的業(yè)務(wù)和UI邏輯。
(2)MVC可以應(yīng)用于簡單的數(shù)據(jù)界面控制邏輯。
(1)Model層
通過抽象出符合業(yè)務(wù)邏輯的Model 層,可以實(shí)現(xiàn)數(shù)據(jù)的保存和處理,并在處理完成后通知UI層更新顯示內(nèi)容。
(2)View層
在Android應(yīng)用中,View層作為用戶界面,通常指的是Activity 的xml 布局文件。這些布局文件定義了用戶界面的組件和布局結(jié)構(gòu),包括各種UI 元素,如按鈕、文本框和圖像等。通過使用這些xml布局文件,可以創(chuàng)建出具有交互性和可視化效果的用戶界面。View實(shí)現(xiàn)程序如下:
(3)Controller層
Controller 層即創(chuàng)建Activity,Controller 層起到了連接View層和Model層的作用,負(fù)責(zé)協(xié)調(diào)界面與數(shù)據(jù)之間的交互。通過處理View層傳遞過來的事件,Controller 層可以響應(yīng)用戶的操作,并將必要的數(shù)據(jù)處理任務(wù)交給Model層來完成。這樣可以實(shí)現(xiàn)界面和數(shù)據(jù)的分離,同時提高代碼的可維護(hù)性和復(fù)用性。
Controller實(shí)現(xiàn)程序如下:
模型-視圖-表示器(Model-View-Presenter,MVP)設(shè)計模式邏輯如圖2所示。
圖2 MVP設(shè)計模式邏輯[9]
Model 作為模型層,負(fù)責(zé)數(shù)據(jù)的加載、存儲和處理,其角色和作用與MVC中的Model層是相同的。
View作為視圖層,負(fù)責(zé)展示界面的數(shù)據(jù)并與用戶進(jìn)行交互。它接收用戶的請求,并將請求傳遞給Presenter進(jìn)行處理。View的角色和作用與MVC中的View層是相對應(yīng)的。
Presenter負(fù)責(zé)邏輯業(yè)務(wù)的處理,接收來自View的用戶請求,并在需要的情況下修改Model,然后通知View進(jìn)行界面的更新顯示。與MVC中的Controller相比,Presenter 的角色和職責(zé)有所區(qū)別。在MVP 架構(gòu)中,Presenter 負(fù)責(zé)處理業(yè)務(wù)邏輯,并起到連接View 和Model的橋梁作用。
(1)View和Model的分離
在MVP 架構(gòu)中,View 負(fù)責(zé)處理用戶界面的展示和用戶輸入的響應(yīng),而Model 負(fù)責(zé)處理數(shù)據(jù)的獲取和處理。二者之間的分離使得修改視圖不會對模型造成影響,也使得View 可以進(jìn)行組件化,提高了代碼的可維護(hù)性和可重用性。
(2)Presenter的復(fù)用和任務(wù)細(xì)分
Presenter 負(fù)責(zé)處理業(yè)務(wù)邏輯和交互邏輯,所有的交互都發(fā)生在Presenter 中。通過將復(fù)雜的任務(wù)分解成細(xì)小的任務(wù),提高代碼的可讀性和可維護(hù)性。而且一個Presenter可以被多個View共享,實(shí)現(xiàn)了Presenter的復(fù)用,減少了代碼的冗余。
(3)接口化的交互
Presenter通過接口和View進(jìn)行交互,通過定義接口來規(guī)范交互方式,有利于測試和維護(hù)。通過接口的使用,可以實(shí)現(xiàn)模塊之間的解耦,方便進(jìn)行單元測試和模塊替換。
(4)通用Presenter和HTTP請求
由于Model 和Presenter 的設(shè)計模式,可以定義多種通用的Presenter,用于處理不同的業(yè)務(wù)邏輯和請求。比如可以定義通用的Presenter用于處理HTTP網(wǎng)絡(luò)請求,并通過即時的HTTP反饋進(jìn)行界面設(shè)置,提高用戶體驗。這也是MVP架構(gòu)的靈活性之一。
(1)接口維護(hù)成本增加
在頁面邏輯復(fù)雜的情況下,隨著功能的增加,對應(yīng)的Presenter 和View 的接口也會增多。這可能增加了代碼的復(fù)雜性和維護(hù)成本??梢钥紤]根據(jù)實(shí)際情況對接口進(jìn)行合理的設(shè)計和劃分,避免接口過于龐大和冗余。
(2)狀態(tài)保存與恢復(fù)
在Android 中,一般使 用OnSaveInstanceState 和OnRestoreInstanceState 來保存和恢復(fù)Activity 的狀態(tài)。然而,在MVP設(shè)計模式中,View不應(yīng)該直接操作Model,這可能導(dǎo)致狀態(tài)的保存和恢復(fù)變得不合理,并增加了Model 和View 之間的耦合性??梢钥紤]使用其他方式來實(shí)現(xiàn)狀態(tài)的保存和恢復(fù),如使用View Model層來管理狀態(tài)。
(3)UI更改導(dǎo)致Presenter接口變更
當(dāng)UI發(fā)生更改時,可能需要對Presenter中的一些接口進(jìn)行修改,存在一定的耦合。這是因為Presenter負(fù)責(zé)處理業(yè)務(wù)邏輯和更新UI??梢钥紤]使用抽象和接口來降低耦合性,并且盡量將UI變更的影響范圍控制在最小范圍內(nèi)。
(1)MVP 不適合應(yīng)用于處理CAN 網(wǎng)絡(luò)相關(guān)的業(yè)務(wù)及UI邏輯。
(2)MVP 適合應(yīng)用于處理HTTP 網(wǎng)絡(luò)相關(guān)的業(yè)務(wù)及UI邏輯。
(1)Model層
Model層負(fù)責(zé)處理數(shù)據(jù)的獲取、存儲和處理,可以包含數(shù)據(jù)庫操作、網(wǎng)絡(luò)請求、文件讀寫等邏輯,并且Model只與Presenter發(fā)生交互。
Model實(shí)現(xiàn)程序如下:
(2)View層
View 層xml 布局 文件和MVC 中View 層的xml 布局文件是相同的。View實(shí)現(xiàn)程序如下:
Activity 達(dá)到接收到View 的事件,通過實(shí)現(xiàn)View的接口[13],通過持有Presenter 的引用,將View 和Presenter進(jìn)行聯(lián)系。
View實(shí)現(xiàn)程序如下:
(3)Presenter層
Presenter負(fù)責(zé)處理業(yè)務(wù)邏輯,通過IPresenter接口實(shí)現(xiàn)View 調(diào)用,它可以定義一系列的方法,用于接收View 層的事件和數(shù)據(jù)請求,并根據(jù)業(yè)務(wù)邏輯進(jìn)行處理,以實(shí)現(xiàn)兩者之間的交互。
Presenter實(shí)現(xiàn)程序如下:
模型-視圖-視圖模型(Model-View-View Model,MVVM)如圖3所示[3,14]。
圖3 MVVM設(shè)計模式邏輯[3]
MVVM 模式可以理解為對MVC 模式的改進(jìn)和優(yōu)化。在MVVM模式中,Model負(fù)責(zé)處理數(shù)據(jù)的加載和存儲,與MVC模式中的Model層設(shè)計策略相同。當(dāng)Model數(shù)據(jù)更新后,它會將新數(shù)據(jù)傳遞給View Model。
View是視圖層,負(fù)責(zé)展示界面數(shù)據(jù)并與用戶進(jìn)行交互,與View Model之間存在雙向交互關(guān)系。View層通過綁定View Model 來實(shí)現(xiàn),當(dāng)ViewModel 的數(shù)據(jù)改變時,View會自動更新相應(yīng)的UI,反之亦然。
View Model 是視圖模型,負(fù)責(zé)完成View 與Model的交互,處理業(yè)務(wù)邏輯,并通知Model進(jìn)行更新操作。
(1)View Model 和View 的耦合度相比MVP 模式更低。View Model 負(fù)責(zé)處理和提供數(shù)據(jù),UI的變化無需特殊處理,只需通過數(shù)據(jù)綁定實(shí)現(xiàn)。這樣做,只需關(guān)注數(shù)據(jù)處理,UI處理也就自然完成了。
(2)View Model 中只包含數(shù)據(jù)和業(yè)務(wù)邏輯,方便進(jìn)行單元測試。
(3)由于車機(jī)CAN網(wǎng)絡(luò)的消息經(jīng)常發(fā)生并且不需要向?qū)?yīng)的ECU發(fā)送請求,同時也會有來自對應(yīng)ECU的反饋消息。因此,MVVM 模式適合用于IVI 車機(jī)端對CAN網(wǎng)絡(luò)的請求,實(shí)現(xiàn)通過數(shù)據(jù)驅(qū)動UI的修改。
盡管使用Data Binding 機(jī)制時,View 層的Data Binding 需要按規(guī)范實(shí)現(xiàn),否則可能導(dǎo)致View 布局問題以及與Activity 中代碼相關(guān)的問題,并且可能不利于調(diào)試,需要一定的開發(fā)經(jīng)驗。但是,由于MVVM 模式能很好地適用于處理與CAN 網(wǎng)絡(luò)相關(guān)的復(fù)雜業(yè)務(wù)和UI邏輯,因此,在基于Android系統(tǒng)的車機(jī)應(yīng)用中訪問CAN網(wǎng)絡(luò)時,MVVM是一種較為理想的設(shè)計模式。
(1)Model層
Model層在MVC、MVP和MVVM 設(shè)計模式中都是負(fù)責(zé)數(shù)據(jù)的加載和處理。在這些設(shè)計模式中,Model層的職責(zé)是從數(shù)據(jù)源獲取數(shù)據(jù),并進(jìn)行數(shù)據(jù)的處理和邏輯操作。
Model實(shí)現(xiàn)程序如下:
(2)View層
此布局與其它設(shè)計模式中的view層的不同之處在于,增加了Data Binding。在使用Data Binding 的情況下,布局文件中的視圖和數(shù)據(jù)源可以直接進(jìn)行綁定,使得數(shù)據(jù)更新和顯示更加自動化和簡潔。通過在布局文件中使用特定的語法和屬性,可以將數(shù)據(jù)源與對應(yīng)的視圖進(jìn)行關(guān)聯(lián),當(dāng)數(shù)據(jù)源發(fā)生變化時,視圖會自動更新。
View實(shí)現(xiàn)程序如下:
MVVM Activity 作用為將View和View Model 進(jìn)行綁定。
MVVM實(shí)現(xiàn)程序如下:
(3)View Model層
View Model 屬于連接視圖層和模型層的中間件,能夠觀察到綁定的數(shù)據(jù)的變化,并對視圖內(nèi)容做對應(yīng)的更新,能夠監(jiān)聽視圖的變化,且通知數(shù)據(jù)發(fā)生改變。
View Model實(shí)現(xiàn)程序如下:
在此項研究中,對MVC、MVP、MVVM 這3種車載Android 應(yīng)用設(shè)計模式進(jìn)行了邏輯分析,并對其優(yōu)缺點(diǎn)進(jìn)行了比較。最后,總結(jié)了在車載終端應(yīng)用中的實(shí)現(xiàn)步驟和結(jié)果。然而,結(jié)合實(shí)際業(yè)務(wù)的實(shí)現(xiàn)中,還需要進(jìn)行更多的設(shè)計工作來進(jìn)行優(yōu)化和細(xì)化。
Android 車載應(yīng)用提供了強(qiáng)大的開發(fā)工具,能夠優(yōu)化用戶交互,并推動了車輛智能化發(fā)展。隨著技術(shù)逐漸進(jìn)步,更多交互、更好體驗的Android應(yīng)用將會在車載終端應(yīng)用。