HarmonyOS 分散チャットルームアプリケーション

HarmonyOS 分散チャットルームアプリケーション

[[434771]]

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHongmengテクノロジーコミュニティ

https://harmonyos..com

導入

以前、[#星光计划1.0# HarmonyOS 分散型 TikTok 風アプリケーション] を紹介しました。今回は、HarmonyOS 分散データ サービスをベースに開発されたチャット ルーム アプリケーションを紹介します。実際のチャットルームでの会話をシミュレートし、友達と交流したり、ストーリーを共有したりすることができます。

効果のデモンストレーション


プロジェクトクラスの説明


主な知識ポイント

分散データサービス

公式紹介: 分散データ サービスは、主にユーザー デバイス内のアプリケーションのデータ コンテンツの分散同期を実現します。デバイス 1 上のアプリケーション A が分散データベース内のデータを追加、削除、または変更すると、デバイス 2 上のアプリケーション A もデータベースの変更を取得できます。要約すると、複数のデバイスが 1 つのデータベースを共有します。

ホームページコード

特に複雑なロジックはなく、分散データサービスの利用が中心で、要所にコメントが入っています。

  1. com.ldd.myapp.bean.ChatDataBean をインポートします。
  2. com.ldd.myapp.provider.ChatProvider をインポートします。
  3. com.ldd.myapp.util.Tools をインポートします。
  4. ohos.aafwk.ability.AbilitySlice をインポートします。
  5. ohos.aafwk.content.Intent をインポートします。
  6. ohos.agp.components.Button をインポートします。
  7. ohos.agp.components.ListContainer をインポートします。
  8. ohos.agp.components.TextField をインポートします。
  9. ohos.app.Context をインポートします。
  10. ohos.bundle.IBundleManager をインポートします。
  11. ohos.data.distributed.common.* をインポートします。
  12. ohos.data.distributed.user .SingleKvStoreをインポートします
  13. ohos.utils.zson.ZSONArray をインポートします。
  14. ohos.utils.zson.ZSONObject をインポートします。
  15.  
  16. java.util.ArrayList をインポートします。
  17. java.util.List をインポートします。
  18.  
  19. 静的ohos.security.SystemPermission.DISTRIBUTED_DATASYNC をインポートします。
  20.  
  21. /**
  22. * ホームページ
  23. */
  24. パブリッククラス MainAbilitySlice は AbilitySlice を拡張します {
  25. プライベートコンテキストmContext;
  26. // チャットリスト
  27. プライベート ListContainer lcList;
  28. //チャットデータ
  29. プライベート最終リスト<ChatDataBean> listData = new ArrayList<>();
  30. //チャットデータアダプタ
  31. プライベート ChatProvider チャットプロバイダー;
  32. // 入力ボックス
  33. プライベート TextField tfContent;
  34. //送信ボタン
  35. プライベートボタン btnSend;
  36.  
  37. // 分散データベースマネージャー
  38. プライベート KvManager kvManager;
  39. // 分散データベース
  40. プライベート SingleKvStore シングルKvストア;
  41. // データベース名
  42. プライベート静的最終文字列 STORE_NAME = "ChatStore" ;
  43. // 保存されたリストデータキー 
  44. プライベート静的最終文字列 KEY_DATA = "key_data" ;
  45. // 保存されたアバターのインデックス
  46. プライベート静的最終文字列 KEY_PIC_INDEX = "key_pic_index" ;
  47. プライベートint picIndex = 0;
  48.  
  49. @オーバーライド
  50. パブリックvoid onStart(インテント インテント) {
  51. super.onStart(インテント);
  52. UIContent をスーパーに設定します。
  53. mContext = これ;
  54. リクエストパーミッション();
  55. コンポーネントを初期化します。
  56. データベースを初期化します。
  57. }
  58.  
  59. /**
  60. * 分散権限を要求する
  61. */
  62. プライベートvoid requestPermission() {
  63. if (verifySelfPermission(DISTRIBUTED_DATASYNC) != IBundleManager.PERMISSION_GRANTED) {
  64. (DISTRIBUTED_DATASYNCの許可をリクエストできる場合){
  65. requestPermissionsFromUser(新しい文字列[]{DISTRIBUTED_DATASYNC}, 0);
  66. }
  67. }
  68. }
  69.  
  70. /**
  71. * コンポーネントを初期化する
  72. */
  73. プライベートvoid initComponent() {
  74. lcList = (ListContainer) リソーステーブルId_lc_list でコンポーネントIDを検索します。
  75. tfContent = (テキストフィールド) findComponentById(ResourceTable.Id_tf_content);
  76. tfContent.setAdjustInputPanel( true );
  77. btnSend = (ボタン) findComponentById(ResourceTable.Id_btn_send);
  78. btnSend.setEnabled( false );
  79.  
  80. // アダプタを初期化する
  81. チャットプロバイダー = 新しいチャットプロバイダー (mContext、リストデータ);
  82. lcList.setItemProvider(チャットプロバイダー);
  83.  
  84. // 入力ボックスの内容変更の監視
  85. tfContent.addTextObserver((テキスト、開始、前、カウント) -> {
  86. btnSend.setEnabled(text.length() != 0);
  87. });
  88. // 送信ボタンをクリック
  89. btnSend.setClickedListener(コンポーネント -> {
  90. 文字列コンテンツ = tfContent.getText().trim();
  91. listData.add (新しい ChatDataBean(Tools.getDeviceId(mContext),picIndex,content));
  92. // データベースに保存
  93. 単一のKvStore.putString(KEY_DATA、ZSONObject.toZSONString(listData));
  94.  
  95. // 入力ボックスをクリアする
  96. tfContent.setText( "" );
  97. });
  98. }
  99.  
  100. /**
  101. * 分散データベースを初期化する
  102. */
  103. プライベートvoid initDatabase() {
  104. // 分散データベースマネージャーを作成する
  105. kvManager = KvManagerFactory.getInstance().createKvManager(新しい KvManagerConfig(this));
  106.  
  107. // データベース構成
  108. オプション options = new Options();
  109. options.setCreateIfMissing( true ) // データベースが存在しない場合に作成するかどうかを設定します
  110. .setEncrypt( false ) // データベースが暗号化されているかどうかを設定します
  111. .setKvStoreType(KvStoreType.SINGLE_VERSION); //データベースタイプ
  112. // 分散データベースを作成する
  113. 単一のKvStore = kvManager.getKvStore(オプション、STORE_NAME);
  114. //データベースデータの変更を監視する
  115. 単一のKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL、新しいKvStoreObserver() {
  116. @オーバーライド
  117. パブリックvoid onChange(ChangeNotification changeNotification) {
  118. リスト<Entry> insertEntries = changeNotification.getInsertEntries();
  119. リスト<Entry> updateEntries = changeNotification.getUpdateEntries();
  120.  
  121. // 初めてデータを保存するときは、insertEntries を取得します
  122. (挿入エントリのサイズ( )>0)の場合{
  123. for (エントリ entry : insertEntries) {
  124. KEY_DATAがentry.getKey()と等しい場合{
  125. // コールバックは非UIスレッドであり、UIはUIスレッドで更新される必要がある
  126. getUITaskDispatcher().syncDispatch(() -> {
  127. リストデータをクリアします。
  128. listData.addAll(ZSONArray.stringToClassList(entry.getValue().getString(),ChatDataBean.class));
  129. チャットプロバイダーに通知データが変更されました();
  130. lcList.scrollTo(リストデータ.size () - 1);
  131. });
  132. }
  133. }
  134. }そうでない場合( updateEntries.size ()>0){
  135. for (エントリ entry : updateEntries) {
  136. KEY_DATAがentry.getKey()と等しい場合{
  137. // コールバックは非UIスレッドであり、UIはUIスレッドで更新される必要がある
  138. getUITaskDispatcher().syncDispatch(() -> {
  139. リストデータをクリアします。
  140. listData.addAll(ZSONArray.stringToClassList(entry.getValue().getString(),ChatDataBean.class));
  141. チャットプロバイダーに通知データが変更されました();
  142. lcList.scrollTo(リストデータ.size () - 1);
  143. });
  144. }
  145. }
  146. }
  147. }
  148. });
  149.  
  150. 試す {
  151. picIndex = singleKvStore.getInt(KEY_PIC_INDEX);
  152. singleKvStore.putInt(KEY_PIC_INDEX, picIndex + 1);
  153. } キャッチ (KvStoreException e) {
  154. e.printStackTrace();
  155. // 見つかりません、最初のエントリ
  156. (e.getKvStoreErrorCode() == KvStoreErrorCode.KEY_NOT_FOUND) の場合 {
  157. picインデックス = 0;
  158. singleKvStore.putInt(KEY_PIC_INDEX, picIndex + 1);
  159. }
  160. }
  161. }
  162.  
  163. @オーバーライド
  164. 保護されたvoid onStop() {
  165. スーパーのonStop();
  166. kvManager.closeKvStore(単一のKvStore);
  167. }
  168. }

シンプルなケース

1. config.json の設定

  1. 「必要な権限」 : [
  2. {
  3. 「理由」 「マルチデバイスコラボレーション」
  4. 「名前」 : 「ohos.permission.DISTRIBUTED_DATASYNC」
  5. 「使用シーン」 : {
  6. "能力" : [
  7. 「メインアビリティ」  
  8. ]、
  9. 「いつ」 「常に」  
  10. }
  11. },
  12. {
  13. 「名前」 : 「ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE」  
  14. },
  15. {
  16. 「名前」 : 「ohos.permission.GET_DISTRIBUTED_DEVICE_INFO」  
  17. },
  18. {
  19. 「名前」 : 「ohos.permission.GET_BUNDLE_INFO」  
  20. }
  21. ]

2. レイアウトページ

  1. <?xml バージョン = "1.0"エンコーディング = "utf-8" ?>
  2. <方向レイアウト
  3. xmlns:ohos= "http://schemas.huawei.com/res/ohos"  
  4. ohos:height= "match_parent"  
  5. ohos:width= "match_parent"  
  6. ohos:alignment= "中央"  
  7. ohos:orientation= "垂直" >
  8.  
  9. <テキスト
  10. ohos:id= "$+id:テキスト"  
  11. ohos:height= "match_content"  
  12. ohos:width= "match_content"  
  13. ohos:text= "データ:0"  
  14. ohos:text_size= "15fp" />
  15.  
  16. <ボタン
  17. ohos:margin= "20vp"  
  18. ohos:id= "$+id:ボタン"  
  19. ohos:height= "match_content"  
  20. ohos:width= "match_parent"  
  21. ohos:background_element= "$graphic:button_bg"  
  22. ohos:padding= "10vp"  
  23. ohos:text= "+1 をクリック"  
  24. ohos:text_color= "白"  
  25. ohos:text_size= "15fp" />
  26.  
  27. </方向レイアウト>

3. MainAbilitySliceコード

  1. ohos.aafwk.ability.AbilitySlice をインポートします。
  2. ohos.aafwk.content.Intent をインポートします。
  3. ohos.agp.components.Button をインポートします。
  4. ohos.agp.components.ListContainer をインポートします。
  5. ohos.agp.components.Text をインポートします。
  6. ohos.agp.components.TextField をインポートします。
  7. ohos.bundle.IBundleManager をインポートします。
  8. ohos.data.distributed.common.* をインポートします。
  9. ohos.data.distributed.user .SingleKvStoreをインポートします
  10. ohos.utils.zson.ZSONArray をインポートします。
  11.  
  12. java.util.List をインポートします。
  13.  
  14. 静的ohos.security.SystemPermission.DISTRIBUTED_DATASYNC をインポートします。
  15.  
  16. パブリッククラス MainAbilitySlice は AbilitySlice を拡張します {
  17. // データを表示
  18. プライベートテキストテキスト;
  19. // 分散データベースマネージャー
  20. プライベート KvManager kvManager;
  21. // 分散データベース
  22. プライベート SingleKvStore シングルKvストア;
  23. // データベース名
  24. プライベート静的最終文字列 STORE_NAME = "MyStore" ;
  25. // 保存するデータキー 
  26. プライベート静的最終文字列 KEY_COUNT = "key_count" ;
  27.  
  28. @オーバーライド
  29. パブリックvoid onStart(インテント インテント) {
  30. super.onStart(インテント);
  31. UIContent をスーパーに設定します。
  32. リクエストパーミッション();
  33. データベースを初期化します。
  34. コンポーネントを初期化します。
  35. }
  36.  
  37. /**
  38. * 分散権限を要求する
  39. */
  40. プライベートvoid requestPermission() {
  41. if (verifySelfPermission(DISTRIBUTED_DATASYNC) != IBundleManager.PERMISSION_GRANTED) {
  42. (DISTRIBUTED_DATASYNCの許可をリクエストできる場合){
  43. requestPermissionsFromUser(新しい文字列[]{DISTRIBUTED_DATASYNC}, 0);
  44. }
  45. }
  46. }
  47.  
  48. /**
  49. * 分散データベースを初期化する
  50. */
  51. プライベートvoid initDatabase() {
  52. // 分散データベースマネージャーを作成する
  53. kvManager = KvManagerFactory.getInstance().createKvManager(新しい KvManagerConfig(this));
  54.  
  55. // データベース構成
  56. オプション options = new Options();
  57. options.setCreateIfMissing( true ) // データベースが存在しない場合に作成するかどうかを設定します
  58. .setEncrypt( false ) // データベースが暗号化されているかどうかを設定します
  59. .setKvStoreType(KvStoreType.SINGLE_VERSION); //データベースタイプ
  60. // 分散データベースを作成する
  61. 単一の KvStore = kvManager.getKvStore(オプション、STORE_NAME);
  62. //データベースデータの変更を監視する
  63. 単一のKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL、新しいKvStoreObserver() {
  64. @オーバーライド
  65. パブリックvoid onChange(ChangeNotification changeNotification) {
  66. リスト<Entry> insertEntries = changeNotification.getInsertEntries();
  67. リスト<エントリ> updateEntries = changeNotification.getUpdateEntries();
  68.  
  69. // 初めてデータを保存するときは、insertEntries を取得します
  70. ( insertEntries.size () > 0)の場合{
  71. for (エントリ entry : insertEntries) {
  72. KEY_COUNTがentry.getKey()と等しい場合{
  73. // コールバックは非UIスレッドであり、UIはUIスレッドで更新される必要がある
  74. getUITaskDispatcher().syncDispatch(() -> {
  75. 整数 カウント= entry.getValue().getInt();
  76. text.setText( "データ: " + count );
  77. });
  78. }
  79. }
  80. }そうでない場合( updateEntries.size () > 0) {
  81. for (エントリ entry : updateEntries) {
  82. KEY_COUNTがentry.getKey()と等しい場合{
  83. // コールバックは非UIスレッドであり、UIはUIスレッドで更新される必要がある
  84. getUITaskDispatcher().syncDispatch(() -> {
  85. 整数 カウント= entry.getValue().getInt();
  86. text.setText( "データ: " + count );
  87. });
  88. }
  89. }
  90. }
  91. }
  92. });
  93.  
  94. }
  95.  
  96. /**
  97. * コンポーネントを初期化する
  98. */
  99. プライベートvoid initComponent() {
  100. テキスト = (テキスト) findComponentById(ResourceTable.Id_text);
  101. ボタン button = (Button) findComponentById(ResourceTable.Id_button);
  102.  
  103. // クリックイベント
  104. button.setClickedListener(コンポーネント -> {
  105. 試す {
  106. 整数 カウント= singleKvStore.getInt(KEY_COUNT);
  107. 単一のKvStore.putInt(KEY_COUNT、カウント+1);
  108. } キャッチ (KvStoreException e) {
  109. e.printStackTrace();
  110. // 見つかりません、最初のエントリ
  111. (e.getKvStoreErrorCode() == KvStoreErrorCode.KEY_NOT_FOUND) の場合 {
  112. 整数 カウント= 0;
  113. 単一のKvStore.putInt(KEY_COUNT、カウント+1);
  114. }
  115. }
  116. });
  117. }
  118. }

コメントは非常に詳細で、主に次の 2 つの点に注目してください。

  1. キーが見つからない状況に対処するために、データを取得するときにtry catchブロックを追加します。
  2. データベース データ変更監視コールバックは非 UI スレッドです。 UI を更新する場合は、UI スレッドに切り替える必要があります。

上記の簡単なケースは、複数のデバイス上の同じアプリケーション間で同じデータベースを使用する分散データ サービスをすぐに習得するのに役立ちます。

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHongmengテクノロジーコミュニティ

https://harmonyos..com

<<:  JavaAgent を使用して JVM を騙す

>>:  マルチクラウド戦略を構築するための考慮事項

推薦する

パフォーマンスと効率の選択は進化する

コンピュータを組み立てたことがある人なら誰でも、マシンのパフォーマンスを追求する方法を知っています。...

クラウドで Redis を使用していますか?知っておくべき10のこと

ステートフル分散システムは大規模に運用するのが難しく、Redis も例外ではありません。マネージド ...

キーワード選択戦略がウェブサイトの最適化に与える影響についての簡単な説明

ウェブサイトのウェブマスターとして、キーワード最適化がネットワーク最適化において非常に重要な位置を占...

B2Bプラットフォームの重みが向上し、ロングテールキーワードがB2Bプラットフォームを有効活用できることが観察されています。

企業のウェブサイトでロングテールキーワードのランキングを獲得するのは簡単ではありません。ウェブサイト...

budgetvm-85% 割引コード/VPS/クラウド サーバー/独立サーバー/サイト全体に共通

budgetvm の新年割引が始まりました。サイト全体で 15% 割引コード: holiday151...

ウェブマスターがウェブサイトの責任者である場合に、ウェブサイトをどのようにマーケティングするかについての簡単な説明

インターネットが変化し続けるにつれて、ウェブサイトで SEO を適切に行うことがますます困難になって...

nexusbytes: ロサンゼルス AMD シリーズ VPS フラッシュセール、年間 27 ドル、1G メモリ/1 コア/10g NVMe/500g 帯域幅

Nexusbytes は現在、米国西海岸のロサンゼルス データ センターの VPS をフラッシュ セ...

インターネットマーケティング市場戦略:自分と敵を知る

オンラインマーケティングでは、何をするにも方向性が必要です。そうでないと、進むべき道が非常に曖昧にな...

高品質の外部リンクをウェブサイトに正しく追加する方法

外部リンクは、ウェブサイトのランキングに影響を与える最も重要な要素の1つです。ランキングの品質は外部...

ブラック 5: MediaTemple-50% オフ/ウェブ ホスティング/WordPress ホスティング

ハイエンド ホスティング ブランド mediatemple.net がついにブラック フライデー セ...

ブランドマーケティングの6つのルール

成功したマーケティングがなければ、成功したビジネスはあり得ません。マーケティング活動は、企業が利益を...

李嘉奇はなぜ勢いを失っているのか?

最近、タオバオのトップライブストリーマーで「人間スオナ」として知られる李佳奇の声が小さくなったようだ...

インターネット大手の海外進出を巡る戦いの簡単な歴史

バイトダンスが最近、ディズニーの幹部をグローバルCOOとして迎え入れたというニュースは大きな話題を呼...

中国インターネット20年: 私の名前はウェブマスターであることを忘れないでください

歴史の車輪は前へ前へと回転する。歴史がインターネット時代に星のように輝くインターネットの有名人を記録...