2020征文-手機(jī) 快速搭建一款鴻蒙分布式分歧終端機(jī)原型
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz
子曾經(jīng)曰過(guò),有鴻蒙,一切皆有可能。
世界上之所以戰(zhàn)火不斷
沖突加劇
根源就是
分歧得不到公正的裁決
我們小時(shí)候都玩過(guò)一種游戲
錘子剪刀布
其實(shí)那是一種解決分歧
最原始最有效的方法
可是為什么我們長(zhǎng)大了以后
就不用這種方法了呢?
因?yàn)樗袃蓚€(gè)弊端
一個(gè)是出手的快慢
另一個(gè)就是臨時(shí)變換手型
分歧終端機(jī)的問(wèn)世
一舉解決了這個(gè)難題
那么,問(wèn)題來(lái)了
這么好的一個(gè)跨時(shí)代的產(chǎn)品
為什么沒(méi)有得到推廣呢?
因?yàn)樗袃蓚€(gè)弊端:
一個(gè)是不方便攜帶
另一個(gè)是……貴(劃掉)……不開(kāi)源
開(kāi)源的鴻蒙分布式分歧終端機(jī)的問(wèn)世
一舉解決了這個(gè)問(wèn)題
那么,構(gòu)建這樣一款鴻蒙分布式分歧終端機(jī)**原型**,需要多長(zhǎng)時(shí)間呢?
10分鐘?
不,
大概要……
一個(gè)周末吧。
具體需要三個(gè)步驟:
第一步,先把家里的娃哄好
第二步,打開(kāi)電腦寫(xiě) Bug(劃掉)代碼
第三步,調(diào)試,如果有問(wèn)題,重復(fù)第二步
萬(wàn)事開(kāi)頭難,第一步永遠(yuǎn)是最難的。
處理好了第一步以后,后兩步就簡(jiǎn)單了,我們來(lái)具體分析一下鴻蒙分布式分歧終端機(jī)原型的設(shè)計(jì)原理。
# 鴻蒙分布式分歧終端機(jī)原型的設(shè)計(jì)
## 首先,需求分析
1). 可以**輸入**各自的決策
2). 由中立第三方進(jìn)行**裁決**
3). 可以**查看**最終的裁決**結(jié)果**
## 其次,模塊劃分。
根據(jù)需求,利用鴻蒙的分布式設(shè)計(jì)思想,我們將分歧終端機(jī)分為兩個(gè)核心模塊:
1). 分歧終端機(jī)的交互模塊,簡(jiǎn)稱(chēng)FA,用于輸入決策和查看結(jié)果
2). 分歧終端機(jī)的計(jì)算模塊,簡(jiǎn)稱(chēng)PA,作為中立第三方,做出最終裁決

## 再次,流程。
假定有A和B兩人發(fā)生分歧,需要解決分歧,那么分歧解決的一個(gè)典型流程可以這樣子:
1). A 啟動(dòng)分歧終端機(jī)的交互模塊(FA-A)
2). B 啟動(dòng)分歧終端機(jī)的交互模塊(FA-B)
3). A 和 B 都連接到同一個(gè)分歧終端機(jī)計(jì)算模塊,假定是計(jì)算模塊A(PA-A)
4). A 和 B 在各自的分歧終端機(jī)的交互模塊上輸入他和她的決策(INPUT-A,INPUT-B)
5). 分歧終端機(jī)的計(jì)算模塊自動(dòng)根據(jù) A 和 B 的輸入,計(jì)算出結(jié)果:RESULT
6). A 和 B 在各自分歧終端機(jī)的交互模塊上查看結(jié)果RESULT,假如B對(duì)結(jié)果不滿意,可以進(jìn)行再次裁決,直到她滿意為止。

## 再次,詳細(xì)設(shè)計(jì)。
### 1. 分歧終端機(jī)交互模塊(FA)
交互模塊需要向使用者提供輸入接口和顯示界面,所以使用的是鴻蒙的FA,也就是 Feature Ability。
FA 也叫Page Ability,而一個(gè)Page可以有多個(gè)Ability Slice(能力切片),也就是子頁(yè)面:

根據(jù)決策過(guò)程的不同階段,我們利用Ability Slice設(shè)計(jì)3個(gè)子頁(yè)面,分別是:
* 1). 初始準(zhǔn)備頁(yè)面,HomeSlice,用于連接分歧終端機(jī)計(jì)算模塊(PA)
這里,我們會(huì)需要用到鴻蒙分布式軟總線的
a). 設(shè)備自動(dòng)發(fā)現(xiàn)能力
對(duì)于在同一個(gè)網(wǎng)絡(luò)下的鴻蒙設(shè)備,在滿足條件的情況下,可以自動(dòng)互相發(fā)現(xiàn),不需要調(diào)用網(wǎng)絡(luò)接口(udp/tcp等),也不需要針對(duì)不同的網(wǎng)絡(luò)狀況(wifi/藍(lán)牙/nfc等) 做不同的實(shí)現(xiàn)。
b). 設(shè)備直連能力
通過(guò)connectAbility接口,可以直接連接需要連接的計(jì)算模塊,不要知道其所在設(shè)備的實(shí)際網(wǎng)絡(luò)情況。
* 2). 等待頁(yè)面,WaitingSlice,先加入分歧解決的人,需要在這個(gè)頁(yè)面上等待其他人加入。
當(dāng)發(fā)現(xiàn)所有人都已經(jīng)加入后,就自動(dòng)進(jìn)入下一個(gè)頁(yè)面,也就是“分歧決策頁(yè)面”。

* 3). 決策頁(yè)面,GameSlice,參與分歧解決的人在這個(gè)頁(yè)面上輸入自己的決策,并查看最終的裁決結(jié)果。

本模塊的技術(shù)要點(diǎn):
1). 子頁(yè)面之間的切換:使用present方法
2). 決策結(jié)果的刷新:可以用計(jì)時(shí)器來(lái)輪詢(xún)結(jié)果,并刷新。
注意
在計(jì)時(shí)器中刷新UI時(shí),相關(guān)代碼需要運(yùn)行在UI線程上,可以使用EventRunner,參考代碼:
- public void runInMainThread(Runnable task){
 - EventRunner runner = EventRunner.getMainEventRunner();
 - EventHandler handler = new EventHandler(runner);
 - handler.postTask(task);
 - }
 - private void startGameLoop(){
 - if(gameTimer == null){
 - gameTimer = new IntervalTimer(1000, 1000) {
 - @Override
 - public void onInterval(long l) {
 - runInMainThread(new Runnable() {
 - @Override
 - public void run() {
 - onLoop(l);
 - }
 - });
 - }
 - @Override
 - public void onFinish() {
 - gameTimer.schedule();
 - }
 - };
 - gameTimer.schedule();
 - }
 - }
 - private void stopGameLoop(){
 - if(gameTimer != null){
 - gameTimer.cancel();
 - gameTimer = null;
 - }
 - }
 
參考文檔
1). Page Ability 開(kāi)發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-page-concept-0000000000033573
2). JAVA UI 框架開(kāi)發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-overview-0000000000500404
### 2. 分歧終端機(jī)核心計(jì)算模塊(PA)
計(jì)算模塊的核心任務(wù)是進(jìn)行數(shù)據(jù)處理,而不需要顯示,所以用到的是鴻蒙的PA,也就是Particle Ability。
計(jì)算模塊需要實(shí)現(xiàn)的功能是:
a). 收集來(lái)自交互模塊的決策輸入
b). 根據(jù)各自的決策來(lái)做出最終裁決
決策過(guò)程,基本上就是一個(gè)判斷 a > b 的過(guò)程,就不贅述了。
技術(shù)要點(diǎn)
1). 連接PA時(shí),使用connectAbility
2). 可能會(huì)有多線程數(shù)據(jù)同步的問(wèn)題
3). 要進(jìn)行跨設(shè)備操作,需要在代碼里,手動(dòng)申請(qǐng)必要的權(quán)限
在項(xiàng)目模塊的 config.json:
- "reqPermissions": [
 - {
 - "name": "ohos.permission.DISTRIBUTED_DATASYNC"
 - },
 - {
 - "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
 - },
 - {
 - "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
 - },
 - {
 - "name": "ohos.permission.GET_BUNDLE_INFO"
 - },
 - {
 - "name": "ohos.permission.servicebus.ACCESS_SERVICE"
 - },
 - {
 - "name": "ohos.permission.servicebus.DISTRIBUTED_DEVICE_STATE_CHANGE"
 - },
 - {
 - "name": "ohos.permission.servicebus.GET_BUNDLE_INFO"
 - }
 - ],
 
在MainAbility啟動(dòng)時(shí)申請(qǐng)權(quán)限:
- public class MainAbility extends Ability {
 - private static final String TAG = MainAbility.class.getSimpleName();
 - @Override
 - public void onStart(Intent intent) {
 - super.onStart(intent);
 - super.setMainRoute(HomeSlice.class.getName());
 - GameClient.getInstance().init();
 - requestPermissionsFromUser(
 - new String[]{
 - "ohos.permission.DISTRIBUTED_DATASYNC",
 - "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO",
 - "ohos.permission.servicebus.ACCESS_SERVICE"
 - }, 0);
 - }
 - }
 
參考文檔
1). Service Ability 開(kāi)發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-service-concept-0000000000044457
2). 分布式任務(wù)調(diào)度
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-distributed-overview-0000001050419345
### 3. 交互模塊與計(jì)算模塊的數(shù)據(jù)通信
既然是兩個(gè)模塊之間要做交互,那么必然就涉及到數(shù)據(jù)通信。
數(shù)據(jù)通信過(guò)程中,除了調(diào)用相關(guān)的通信接口以外,另一個(gè)很重要的點(diǎn)就是要對(duì)數(shù)據(jù)進(jìn)行封包和解包。
整個(gè)通信過(guò)程,是通過(guò)鴻蒙分布式軟總線來(lái)完成的。
我們當(dāng)然可以利用軟總線提供的接口來(lái)實(shí)現(xiàn)通信過(guò)程,并自己定義數(shù)據(jù)結(jié)構(gòu)、以及封包和解包的方法。
但是,這樣就沒(méi)辦法在10分鐘內(nèi)完成了。
幸運(yùn)的是,鴻蒙提供了一個(gè)很方便的工具,IDL(鴻蒙接口定義語(yǔ)言),來(lái)幫我們完成這個(gè)讓人頭禿的工作。
> IDL官方文檔
> https://developer.harmonyos.com/cn/docs/documentation/doc-references/idl-overview-0000001050762835
利用IDL工具,只需要3步,就可以實(shí)現(xiàn)數(shù)據(jù)通信功能:
1). 在IDL文件中定義好接口,方法,方法的輸入輸出參數(shù)
2). 利用DevEco Studio工具將IDL文件轉(zhuǎn)換為代碼
3). 實(shí)現(xiàn)具體的業(yè)務(wù)邏輯
定義好接口以后,我們就可以像調(diào)用本地方法一樣,調(diào)用遠(yuǎn)程方法了。
IDL 代碼示例:
- // IGameServiceInterface.idl
 - // Declare any non-default types here with sequenceable or interface statements
 - // 申明一個(gè)可序列化的結(jié)構(gòu),具體的定義在Java中編寫(xiě),詳情參看IDL文檔
 - sequenceable com.blackshadowgame.rps.GameResultData;
 - interface com.blackshadowgame.rps.IGameServiceInterface {
 - int echo([in] int a);
 - // 加入游戲
 - int joinGame([in] String playerId);
 - // 與AI對(duì)決
 - int playWithAI([in] int pid);
 - // 獲取當(dāng)前局的對(duì)手列表
 - int[] getPlayers([in] int pid);
 - // 出拳
 - int sendInput([in] int pid, [in] int inputCode);
 - // 查詢(xún)結(jié)果
 - GameResultData queryGameResult([in] int pid);
 - // 離開(kāi)游戲
 - int leaveGame([in] int pid);
 - int nextGame([in] int pid);
 - }
 
### 4. 組裝和測(cè)試
現(xiàn)在各個(gè)模塊都準(zhǔn)備好了,將 FA/PA/IDL 組裝起來(lái),進(jìn)行
聯(lián)......
調(diào)......
測(cè)......
試......
如果你足夠幸運(yùn)的話,可能10分鐘就調(diào)試完畢,如果不夠幸運(yùn),經(jīng)過(guò)無(wú)數(shù)次測(cè)試和修改,最終也能調(diào)試出沒(méi)有明顯bug的版本進(jìn)行體驗(yàn)。

這樣,一款鴻蒙分布式分歧終端機(jī)原型,就完成了!
### 6. 關(guān)于界面美化
你說(shuō)需要對(duì)界面進(jìn)行美化?
## Pro 版本
鴻蒙分布式分歧終端機(jī)還可以升級(jí)到Pro版,增加更多“Profession”的功能。利用鴻蒙的分布式能力,這些都可以很輕松實(shí)現(xiàn),例如:
1). AI切磋:供無(wú)聊人士進(jìn)行切磋
2). 圍觀:供吃瓜群眾圍觀分歧決策過(guò)程
3). 多人切磋:超過(guò)2人以上切磋的玩法
4). 邀請(qǐng)/強(qiáng)制切磋:邀請(qǐng)他人參與切磋的玩法
5). 任意設(shè)備切磋:除了手機(jī),支持其他設(shè)備作為輸入進(jìn)行切磋,例如手表等
6). 大屏協(xié)同切磋:切磋玩家在自己的設(shè)備上輸入,然后在大屏上顯示結(jié)果
## 開(kāi)源代碼
本項(xiàng)目代碼已經(jīng)上傳到gitee,供大家參考一下。
> https://gitee.com/devonzhang/rock-paper-scissors

## 參考文獻(xiàn)
完成本項(xiàng)目所需要的技能點(diǎn),都可以通過(guò)在鴻蒙OS開(kāi)發(fā)者官網(wǎng)上找到學(xué)習(xí)資料。
1). 鴻蒙OS應(yīng)用開(kāi)發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/document-outline-0000001064589184
2). Ability 開(kāi)發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-ability-overview-0000000000029852
3). Page Ability 開(kāi)發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-page-concept-0000000000033573
4). Service Ability 開(kāi)發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-service-concept-0000000000044457
5). 分布式任務(wù)調(diào)度
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-distributed-overview-0000001050419345
6). JAVA UI 框架開(kāi)發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-overview-0000000000500404
7). 鴻蒙OS IDL接口使用規(guī)范
https://developer.harmonyos.com/cn/docs/documentation/doc-references/idl-overview-0000001050762835
## 最后
本項(xiàng)目代碼僅供學(xué)習(xí)之用,請(qǐng)勿直接使用到生產(chǎn)環(huán)境中,如果出現(xiàn)bug,概不負(fù)責(zé)~
# 最后的最后
既然你已經(jīng)看到這里,我是阿斌,一個(gè)全棧游戲開(kāi)發(fā),歡迎
1. 訂閱我的鴻蒙學(xué)習(xí)專(zhuān)欄:《跟阿斌一起學(xué)鴻蒙》 https://harmonyos.51cto.com/column/25
2. 關(guān)注我的個(gè)人公眾號(hào):耿直的IT男阿斌
3. 查看我的技術(shù)博客:https://xmanyou.com/
©著作權(quán)歸作者和HarmonyOS技術(shù)社區(qū)共同所有,如需轉(zhuǎn)載,請(qǐng)注明出處,否則將追究法律責(zé)任
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz



















 
 
 










 
 
 
 