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

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

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

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

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

本模塊的技術(shù)要點:
1). 子頁面之間的切換:使用present方法
2). 決策結(jié)果的刷新:可以用計時器來輪詢結(jié)果,并刷新。
注意
在計時器中刷新UI時,相關(guā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 開發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ability-page-concept-0000000000033573
2). JAVA UI 框架開發(fā)指南
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-overview-0000000000500404
### 2. 分歧終端機核心計算模塊(PA)
計算模塊的核心任務(wù)是進行數(shù)據(jù)處理,而不需要顯示,所以用到的是鴻蒙的PA,也就是Particle Ability。
計算模塊需要實現(xiàn)的功能是:
a). 收集來自交互模塊的決策輸入
b). 根據(jù)各自的決策來做出最終裁決
決策過程,基本上就是一個判斷 a > b 的過程,就不贅述了。
技術(shù)要點
1). 連接PA時,使用connectAbility
2). 可能會有多線程數(shù)據(jù)同步的問題
3). 要進行跨設(shè)備操作,需要在代碼里,手動申請必要的權(quán)限
在項目模塊的 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啟動時申請權(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 開發(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. 交互模塊與計算模塊的數(shù)據(jù)通信
既然是兩個模塊之間要做交互,那么必然就涉及到數(shù)據(jù)通信。
數(shù)據(jù)通信過程中,除了調(diào)用相關(guān)的通信接口以外,另一個很重要的點就是要對數(shù)據(jù)進行封包和解包。
整個通信過程,是通過鴻蒙分布式軟總線來完成的。
我們當(dāng)然可以利用軟總線提供的接口來實現(xiàn)通信過程,并自己定義數(shù)據(jù)結(jié)構(gòu)、以及封包和解包的方法。
但是,這樣就沒辦法在10分鐘內(nèi)完成了。
幸運的是,鴻蒙提供了一個很方便的工具,IDL(鴻蒙接口定義語言),來幫我們完成這個讓人頭禿的工作。
> IDL官方文檔
> https://developer.harmonyos.com/cn/docs/documentation/doc-references/idl-overview-0000001050762835
利用IDL工具,只需要3步,就可以實現(xiàn)數(shù)據(jù)通信功能:
1). 在IDL文件中定義好接口,方法,方法的輸入輸出參數(shù)
2). 利用DevEco Studio工具將IDL文件轉(zhuǎn)換為代碼
3). 實現(xiàn)具體的業(yè)務(wù)邏輯
定義好接口以后,我們就可以像調(diào)用本地方法一樣,調(diào)用遠程方法了。
IDL 代碼示例:
- // IGameServiceInterface.idl
- // Declare any non-default types here with sequenceable or interface statements
- // 申明一個可序列化的結(jié)構(gòu),具體的定義在Java中編寫,詳情參看IDL文檔
- sequenceable com.blackshadowgame.rps.GameResultData;
- interface com.blackshadowgame.rps.IGameServiceInterface {
- int echo([in] int a);
- // 加入游戲
- int joinGame([in] String playerId);
- // 與AI對決
- int playWithAI([in] int pid);
- // 獲取當(dāng)前局的對手列表
- int[] getPlayers([in] int pid);
- // 出拳
- int sendInput([in] int pid, [in] int inputCode);
- // 查詢結(jié)果
- GameResultData queryGameResult([in] int pid);
- // 離開游戲
- int leaveGame([in] int pid);
- int nextGame([in] int pid);
- }
### 4. 組裝和測試
現(xiàn)在各個模塊都準備好了,將 FA/PA/IDL 組裝起來,進行
聯(lián)......
調(diào)......
測......
試......
如果你足夠幸運的話,可能10分鐘就調(diào)試完畢,如果不夠幸運,經(jīng)過無數(shù)次測試和修改,最終也能調(diào)試出沒有明顯bug的版本進行體驗。

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

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