邵毅 何美 陳春
關(guān)鍵詞:Flutter;Golang;Socket;山羊孕測
中圖分類號(hào):TP311 文獻(xiàn)標(biāo)識(shí)碼:A
文章編號(hào):1009-3044(2023)03-0040-04
隨著移動(dòng)應(yīng)用在廣大群眾中的廣泛使用頻率提高,更多的B端產(chǎn)品逐步轉(zhuǎn)向到移動(dòng)端,其中原生App 的高性能滿足較多場景的使用,隨著技術(shù)發(fā)展,跨平臺(tái)方案逐步推廣,引出眾多跨平臺(tái)技術(shù),如React Native、Weex、Flutter等。2018年谷歌開源Flutter1.0至今3.3 在跨平臺(tái)的高性能與開發(fā)便捷不斷受到廣泛青睞。本文將在已使用Java SpringBoot設(shè)計(jì)的山羊孕測管理系統(tǒng)平臺(tái)的基礎(chǔ)上采用Flutter框架開發(fā)一套山羊孕測App,實(shí)現(xiàn)視頻監(jiān)控、即時(shí)通訊、異常通知等功能,為提升與山羊孕測管理系統(tǒng)平臺(tái)的高性能多線程數(shù)據(jù)處理能力使用Golang語言開發(fā)接口SDK包。有效提高專家、管理員、員工通過App進(jìn)行對山羊懷孕檢測、山羊狀態(tài)進(jìn)行監(jiān)控與管理,使用Flutter進(jìn)行一套代碼開發(fā),編譯出原生代碼在Android、iOS平臺(tái)上運(yùn)行,節(jié)省了開發(fā)成本,同時(shí)也提高了App的運(yùn)行效率。
1 山羊孕測App 設(shè)計(jì)
1.1 Flutter 框架介紹
Flutter 是Google 開源的應(yīng)用開發(fā)框架,使用Dart 語言開發(fā),僅需要一套代碼就能構(gòu)建精美的、原生平臺(tái)編譯的多平臺(tái)應(yīng)用軟件。Flutter可快速直接編譯成ARM或者Intel 平臺(tái)的機(jī)械代碼,確保擁有原生平臺(tái)運(yùn)行的性能表現(xiàn)能力,高效地使用熱重載(Hot Reload) 在開發(fā)中快速更新實(shí)時(shí)預(yù)覽并不丟失狀態(tài),在屏幕上,可靈活地將每個(gè)像素都由你來把握。在Flutter3.3版本開始逐步引入新的圖形引擎: Impeller,提供了絲滑的動(dòng)畫效果,使用Impeller 的應(yīng)用可以保持60Hz 或者更快的刷新率的同時(shí),能夠比以前更進(jìn)一步地突破界限。Flutter代碼由Dart語言編寫,該語言提供允許編譯為iOS和Android的32位和64位的機(jī)械碼,以及在Web 允許的JavaScript和桌面設(shè)備,并且開源、免費(fèi)和社區(qū)開發(fā)者的不斷增加,現(xiàn)已被廣大開發(fā)者使用[1]。
1.2 Go語言介紹
Go語言(Golang) 起源于2007 年,是由Google 的Robert Griesemer,Rob Pike 及Ken Thompson 開發(fā)的一門編譯型語言。具有部署簡單、并發(fā)性能好、設(shè)計(jì)與執(zhí)行能力好、支持垃圾回收功能、跨平臺(tái)編譯運(yùn)行等優(yōu)點(diǎn)。具有Gomobile是一個(gè)應(yīng)用于iOS和Android 的優(yōu)秀跨平臺(tái)開發(fā)庫,為開發(fā)者提供創(chuàng)建Android或iOS移動(dòng)平臺(tái)代碼的工具。
1.3 山羊孕測設(shè)計(jì)
針對性能與降低開發(fā)成本,F(xiàn)lutter具有較好的狀態(tài)管理以及極快的UI便捷開發(fā)與跨平臺(tái)的支持。在實(shí)時(shí)數(shù)據(jù)更新與數(shù)據(jù)接口請求,考慮到高并發(fā)、跨平臺(tái)、低成本開發(fā)[2],使用Socket連接,實(shí)時(shí)進(jìn)行數(shù)據(jù)通信觸發(fā)數(shù)據(jù)更新接口下發(fā)更新通知,從性能方面考慮,選擇使用Go語言進(jìn)行編寫后端與App之間數(shù)據(jù)交互的橋梁,編譯出與后端數(shù)據(jù)交互的SDK,方便在多場景下集成使用[3]。并使用Flutter 提供Method?Channel通信方式,在Native和Flutter的進(jìn)行調(diào)用原生的代碼。其中用到狀態(tài)管理插件在Provider、GetX、Bloc、Redux中從難易度上考慮,其中Provider的使用簡便,但是它需要更多的框架搭建與處理全局上下文的問題,因此選擇GetX狀態(tài)管理,它的使用簡單,并對全局context上下文提供了對應(yīng)的方法,在業(yè)務(wù)邏輯中方便地調(diào)用以及對各個(gè)頁面之間進(jìn)行跨頁面的狀態(tài)更新。避免過多重復(fù)的Widget 組件實(shí)現(xiàn),對重復(fù)使用頻率高的組件進(jìn)行封裝,提高了代碼質(zhì)量,方便在各個(gè)頁面之間直接調(diào)用,避免重復(fù)UI 邏輯實(shí)現(xiàn),并針對重復(fù)調(diào)用方法邏輯進(jìn)行封裝到統(tǒng)一的Controller 控制器中由GetX狀態(tài)管理方便調(diào)用,提高了代碼閱讀性[4]。
1.4 山羊孕測App網(wǎng)絡(luò)請求拓?fù)鋱D
山羊孕測App首次啟動(dòng)進(jìn)行登錄,向后端發(fā)送請求,通過網(wǎng)關(guān)授權(quán)后從后端應(yīng)用服務(wù)器獲取數(shù)據(jù)信息進(jìn)行初始化SDK接口并建立Socket 連接,監(jiān)聽數(shù)據(jù)更新。當(dāng)觸發(fā)監(jiān)控頁面時(shí)連接視頻監(jiān)控視頻推流地址呈現(xiàn)畫面在App,所有數(shù)據(jù)通過SDK進(jìn)行發(fā)起數(shù)據(jù)請求返回到App呈現(xiàn)數(shù)據(jù)。在避免重復(fù)的登錄操作,使用了無狀態(tài)Token 校驗(yàn)權(quán)限,在每個(gè)請求中均攜帶Token請求,后端服務(wù)校驗(yàn)通過后,返回?cái)?shù)據(jù)[5]。圖1為網(wǎng)絡(luò)請求拓?fù)鋱D。
1.5 山羊孕測App 功能
山羊孕測App底部導(dǎo)航主要?jiǎng)澐譃槭醉?、資訊、消息、我的四個(gè)主要頁面入口。首頁:包含山羊數(shù)據(jù)列表,每個(gè)山羊可點(diǎn)擊查看具體基本信息、其他觀察、超聲波、預(yù)警推送、生物激素、專家意見、視頻監(jiān)控、當(dāng)日事件等功能。資訊:提供相關(guān)的資訊內(nèi)容閱讀。消息:為增強(qiáng)即時(shí)通訊能力,用于專家、員工、管理員之間的消息即時(shí)溝通能力。我的:提供個(gè)人信息資料修改,管理員可對用戶和山羊信息進(jìn)行管理維護(hù),功能結(jié)構(gòu)如圖2-①。除消息頁面(即時(shí)通訊)為通用功能、資訊頁面與我的頁面?zhèn)€人信息修改外,在登錄頁面可以通過申請賬號(hào)功能頁面申請賬號(hào)、忘記密碼、登錄賬號(hào)三項(xiàng)功能,在登錄成功后根據(jù)申請賬號(hào)時(shí)申請的角色權(quán)限不同將功能細(xì)分:管理員擁有管理后臺(tái)、推送版本、修改參數(shù)功能,專家與員工角色同時(shí)具備查看信息、查看監(jiān)控、推送預(yù)警、日歷事件,專家額外擁有編輯建議、推送狀態(tài)功能權(quán)限,員工額外擁有上傳圖片權(quán)限。如圖2-②所示。
2 山羊孕測實(shí)現(xiàn)與關(guān)鍵技術(shù)
2.1 服務(wù)端與App端數(shù)據(jù)交互
Flutter編寫App在進(jìn)行數(shù)據(jù)交互時(shí)候,需要與后端業(yè)務(wù)通過API接口與Socket通道進(jìn)行交互。在本App設(shè)計(jì)中使用Golang對后端業(yè)務(wù)接口進(jìn)行封裝成SDK API,F(xiàn)lutter需要進(jìn)行SDK初始化后端接口地址,通過調(diào)用接口與后端進(jìn)行交互,并使用SDK初始化Socket建立連接,實(shí)時(shí)更新山羊狀態(tài)數(shù)據(jù),通過GetX 狀態(tài)管理對UI狀態(tài)更新。
2.2 App 頁面功能實(shí)現(xiàn)[6]
圖3為山羊孕測App實(shí)現(xiàn)部分頁面圖,詳情見下:
1) 底部導(dǎo)航:使用自定義BuildNavigation底部導(dǎo)航組件傳入Scaffold 腳手架的bottomNavigationBar 生成底部導(dǎo)航,在腳手架body中使用IndexedStack組件記錄當(dāng)前導(dǎo)航索引進(jìn)行切換頁面,效果如圖3-① 所示。
2) 首頁:使用GetX中Controller控制器初始化數(shù)據(jù)并建立Socket連接監(jiān)聽數(shù)據(jù)變化,關(guān)鍵代碼如下:
initSocket() async {
var socket = await Socket.connect(Api.socket, Api.
socketPort);
socket.listen((event) {
initAllSheepData();
update(['MainMHO']);
});
使用card_swiper插件完成輪播組件,選項(xiàng)卡區(qū)域使用TabBar組件實(shí)現(xiàn),效果如圖3-②所示,選項(xiàng)卡中數(shù)據(jù)使用GetBuilder定義id并包裹ListView列表組件加載山羊數(shù)據(jù),在監(jiān)聽數(shù)據(jù)變化時(shí),通過GetX中up?date()方法傳入定義id值進(jìn)行局部組件更新。
在點(diǎn)擊每個(gè)山羊詳情卡片式組件進(jìn)入詳情頁面時(shí)候,優(yōu)先進(jìn)行權(quán)限校驗(yàn),根據(jù)權(quán)限不同,所使用的功能權(quán)限不同。在無權(quán)限時(shí)將提示無權(quán)訪問彈窗并返回至首頁。所有按鈕使用GestureDetector與Container 進(jìn)行封裝成可自定義顏色、圖片、內(nèi)容的Widget組件,避免過多重復(fù)代碼編寫。員工使用確定懷孕與取消確定觸發(fā)Socket發(fā)送廣播通知其他在線用戶狀態(tài)更新,關(guān)鍵代碼如下:
putDescribe(int id, String msg) {
Get.back();
SheepApi.putSheep({
"sheepId": id,
"sheepDescribe": msg,
}).then((value) {
initSheepData(state. sheepModel. value. data!.
sheepId?。?
});
包含了生物激素,超聲波,其他觀察,運(yùn)動(dòng),溫度,日歷,智慧耳標(biāo),視頻監(jiān)控,AI助手、當(dāng)日記事,預(yù)警推送、取消預(yù)警,專家意見。點(diǎn)擊進(jìn)入“生物激素,超聲波,其他觀察,運(yùn)動(dòng),溫度,日歷,智慧耳標(biāo),視頻監(jiān)控”可以進(jìn)入功能詳情頁查看信息執(zhí)行相關(guān)操作。通過各指標(biāo)信息的查看,管理員點(diǎn)擊進(jìn)入“預(yù)警推送、取消預(yù)警”可以對山羊是否懷孕進(jìn)行預(yù)警和撤銷。點(diǎn)擊進(jìn)入“專家意見”可以查看專家給的相關(guān)意見,但不能修改。點(diǎn)擊進(jìn)入“AI助手”,可為將來AI功能提供擴(kuò)展接口。點(diǎn)擊進(jìn)入“當(dāng)日記事”,可在日歷記錄當(dāng)日山羊情況[7],效果如圖3-③所示。
專家登錄時(shí),可對專家意見中內(nèi)容進(jìn)行編輯,內(nèi)容編輯使用flutter_quill富文本插件實(shí)現(xiàn),員工只能進(jìn)行查看內(nèi)容不可編輯,效果如圖3-④ 所示。
運(yùn)動(dòng)與溫度數(shù)據(jù)通過調(diào)用后端接口獲取傳感器數(shù)據(jù)得到當(dāng)天每半小時(shí)的數(shù)據(jù)[8]。其中日歷部分使用bruno 插件完成UI功能,并可通過當(dāng)日記事按鈕提交當(dāng)日事件記錄。關(guān)鍵代碼如下:
changeDateTime(DateTime date?Time) {
String calendarDate = ' ${dateTime.
year} - ${dateTime. month} - ${dateTime.
day}';
CalendarApi.getCalendarByDate(
Get. arguments['sheepId']. toString(),
calendarDate, '1')
.then((value) {
state. listCalendarModel. value =
value.data!;
});
}
void postCalendar() {
var date = DateTime.now();
String calendarDate = '${date.year}-${date.month}-
${date.day}';
CalendarApi.postCalendar(
Get.arguments.toString(),
calendarDate,
'1',
'山羊狀況記錄: ${state.text}',
).then((value) {
if (value.data!.code == 20000) {
contextFocusNode.unfocus();
Get.dialog(
ShowLoading(
text: '${value.data!.msg}',
),
).then((value) {
Get.back();
});
}
});
}
視頻監(jiān)控頁面在完成后端數(shù)據(jù)鑒權(quán)后獲取到監(jiān)控視頻推流地址,路由并攜帶推流地址到視頻播放頁面,通過調(diào)用better_player插件初始化后,視頻進(jìn)行加載播放,在返回頁面時(shí)候銷毀播放器避免視頻常駐后臺(tái)播放占用內(nèi)存與帶寬占用,關(guān)鍵代碼如下:
AspectRatio(
aspectRatio: 16 / 9,
child: BetterPlayer.network(
Get.arguments,
betterPlayerConfiguration: const BetterPlayerCon?
figuration(
autoPlay: true,
aspectRatio: 16 / 9,
),
)3) 資訊:通過調(diào)用封裝的SDK接口,請求資訊數(shù)據(jù),效果如圖3-⑤所示。初始加載20條數(shù)據(jù)并在滑動(dòng)頁面最后一條數(shù)據(jù)時(shí)觸發(fā)加載更多數(shù)據(jù),每次觸發(fā)加載遞增20條數(shù)據(jù),關(guān)鍵代碼如下:
void initNewsData() {
NewsApi. getPageNews(current: current, pageSize:
pageSize).then((value) {
state.listNewsModel.value = value.data!;
});
}4) 消息:為了方便工作人員之間的及時(shí)的溝通處理能力,集成tim_ui_kit插件,完成簡單的即時(shí)通訊功能業(yè)務(wù)能力[9],效果如圖3-⑥所示。關(guān)鍵代碼如下:
initTencentIMSdk() {
_coreInstance.init(
sdkAppID: Config.sdkAppID,
loglevel: LogLevelEnum.V2TIM_LOG_DEBUG,
listener: V2TimSDKListener());
}
final MessageState state = MessageState();
final TIMUIKitConversationController controller =
TIMUIKitConversationController();
@override
void onInit() async {
super.onInit();
controller.loadData();
controller.setConversationListener(
listener: V2TimConversationListener(
onNewConversation: (conv) {
update();
},
onConversationChanged: (conv) {
update();
},
),
);
}5) 我的:調(diào)用封裝的SDK獲取個(gè)人信息后,通過個(gè)人信息中指定角色判斷,管理將額外顯示用戶管理、山羊管理入口按鈕,效果如上圖3-⑦所示。關(guān)鍵代碼如下:
void updateUserInfo() {
String? faceUrl;
if (state.faceUrl.value != '') {
faceUrl = state.faceUrl.value;
}
UserApi.updateUserInfo(
state.userInfo.value.data!.userId!,
faceUrl!,
nicknameController!.text,
emailController!.text,
).then((value) async {
// 更新IM頭像
V2TimUserFullInfo userFullInfo = V2TimUserFull?
Info();
userFullInfo. userID = state. userInfo. value. data!.
username;
userFullInfo.faceUrl = Api.baseUrl + faceUrl!;
userFullInfo.nickName =
nicknameController!. text ! = '' ? nicknameCon?
troller!.text : '';
V2TimCallback v2timCallback = await TIMUIKit?
Core.getSDKInstance()
.setSelfInfo(userFullInfo: userFullInfo);
if (v2timCallback.code == 0) {
iniUserInfo();
Get.back();
}
});
}
3 性能效果分析
通過Android Studio 的Flutter 插件提供的FlutterInspector進(jìn)行調(diào)試觀察FPS浮動(dòng)情況,得到一個(gè)良好的效果,均保持在60FPS左右的范圍,如圖3-⑧所示。通過校內(nèi)學(xué)生100人在多種不同機(jī)型的安裝下使用,對山羊孕測App進(jìn)行多個(gè)頁面的高頻率反復(fù)隨機(jī)點(diǎn)擊操作和查看各種功能,無任何閃退情況,各項(xiàng)功能正常。Socket連接中無斷連,并均能收到實(shí)時(shí)數(shù)據(jù)更新提示,消息的互發(fā)及時(shí)溝通無任何數(shù)據(jù)丟失。
4 結(jié)束語
山羊孕測App的開發(fā),通過對業(yè)務(wù)框架設(shè)計(jì),將業(yè)務(wù)邏輯、UI、數(shù)據(jù)分離設(shè)計(jì)開發(fā),降低耦合性,對各項(xiàng)傳感器的高性能連接,保障了產(chǎn)品業(yè)務(wù)的高可用性。通過Flutter與Go語言的跨平臺(tái)特性節(jié)省了開發(fā)成本。