HarmonyOS 分散型親子教育

HarmonyOS 分散型親子教育

[[412544]]

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

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

https://harmonyos..com

1. プロジェクトの紹介

遠隔教育とマルチスクリーンコラボレーションは、スマート教育にとって重要なシナリオです。このコードラボでは、親子の早期教育システムを使用して、分散型早期教育算数問題と分散型ジグソーパズル ゲームという 2 つの包括的なケースを完了します。開発者が HarmonyOS アプリケーション開発、マルチスクリーン インタラクション、分散型クロスデバイス コラボレーションのエクスペリエンスを迅速に理解できるようにすることを目的としています。

このコードラボでは、Page Ability、Service Ability、Intent、分散タスク スケジューリング、パブリック イベントなどの紹介に重点を置きます。同時に、マルチスクリーン インタラクション、分散クロスデバイス コラボレーション、描画キャンバスの使用、古典的なパズル アルゴリズムについても紹介します。正式な紹介の前に、まずはこのコードラボで実装されている機能をすぐに理解していただけるよう、親子の早期教育システムのデモンストレーションを行います。

機能1: 幼児期の算数問題

幼児向けの算数問題をクリックすると、システムがランダムに 2 桁の加算問題を表示します。リアルタイム指導をクリックすると、2 つのキャンバスが表示されます。ローカル側ではドラフト計算に黒の手書き文字を使用し、リモート側ではリアルタイムのガイダンスに赤の手書き文字を使用できます。操作手順は両端でリアルタイムに同期されます。効果図を以下に示します。


機能2: ジグソーパズルゲーム

ジグソーパズルゲームをクリックすると、9 マスのジグソーパズルゲームが表示され (画像はランダムに配置されます)、画像をクリックするとパズルが完成します。ローカル側で親子コラボレーションをクリックすると、リモート側に同一のゲーム ページが表示されます。 2 つのデバイスはリアルタイムで相互作用し、写真を同期してつなぎ合わせることができ、操作手順もリアルタイムで同期できます。効果図を以下に示します。


上記の 2 つの親子ゲームがどのように実装されるかを知りたいですか?ぜひ私たちのコードラボで学んでください。

2. HarmonyOS環境を構築する

HarmonyOS環境を構築する

  • DevEco Studio をインストールします。詳細については、DevEco Studio のダウンロードを参照してください。
  • DevEco Studio 開発環境をセットアップします。 DevEco Studio 開発環境はネットワーク環境に依存する必要があります。ツールを正常に使用するには、ネットワークに接続する必要があります。次の 2 つの状況に応じて開発環境を構成できます。
  1. インターネットに直接アクセスできる場合は、HarmonyOS SDK をダウンロードするだけです。
  2. ネットワークがインターネットに直接アクセスできず、プロキシサーバー経由でアクセスする必要がある場合は、開発環境の構成を参照してください。

例:

プログラムを携帯電話で実行する必要がある場合は、事前に証明書を申請する必要があります。シミュレータを使用する場合はこれを無視できます。

キーと証明書要求ファイルを準備する

試運転証明書を申請する

この CodeLab は、次の機器を使用して完了できます。

開発者モードをオンにした実際のHarmonyOSデバイス

DevEco Studio のモバイル エミュレータ (エミュレータは現在分散デバッグをサポートしていません)

3. コード構造の解釈

このコードラボでは、コアコードのみを説明します。完全なコードは最後のリファレンスからダウンロードできます。まず、プロジェクト全体のコード構造を紹介します。


  • devices: デバイス選択ダイアログをカプセル化します。 SelectDeviceDialog で関連メソッドを直接呼び出すことができます。
  • point: 描画関連の関数をカプセル化しており、DrawPoint 内の関連メソッドを直接呼び出すことができます。
  • スライス: MainAbilitySlice はアプリケーションのメイン ページ、MathGameAbilitySlice は幼児向け算数問題のメイン ページ、MathDrawRemSlice は幼児向け算数描画ページ、PictureGameAbilitySlice はジグソー パズル ゲームのメイン ページです。
  • utils: パブリック メソッドとパブリック データをカプセル化します。
  • MathGameServiceAbility、PictureGameServiceAbility: リモート接続用のサービス機能。
  • resources: プロジェクトで使用されるリソース ファイル (resources\base\layout の下の XML レイアウト ファイルや resources\base\media の下の画像リソースなど) を保存します。
  • config.json: 設定ファイル。

4. 親子早期教育システムのページフロー

親子早期教育システムのメインページと各ゲームページのレイアウトを下図に示します。まず最初に、関連するレイアウトコードを紹介します。

ホームページのレイアウトファイルは ability_main.xml で、ページ制御ロジックは MainAbilitySlice です。早期教育システムのレイアウト ファイルは math_game.xml で、ページ制御ロジックは MathGameAbilitySlice です。ジグソーゲームのレイアウトファイルは ability_picture.xml で、ページ制御ロジックは PictureGameAbilitySlice です。ページのフローを実現するには、まず MainAbility でルーティングを設定し、MainAbilitySlice でボタン クリック イベントを実装する必要があります。

幼児の算数の問題にジャンプする例を挙げると、まず MainAbility でルートを設定する必要があります。コードは次のとおりです。

  1. アクションルートを追加します(CommonData.MATH_PAGE、MathGameAbilitySlice.class.getName());

次に、MainAbilitySlice にクリック イベントを追加する必要があります。コードは次のとおりです。

  1. プライベートvoid mathGame() {
  2. LogUtil.info(TAG, "ResourceTable Id_math_game をクリックします" );
  3. インテント mathGameIntent = new Intent();
  4. 操作operationMath = new Intent.OperationBuilder()
  5. .withBundleName(バンドル名を取得())
  6. .withAbilityName(CommonData.ABILITY_MAIN)
  7. .withAction(CommonData.MATH_PAGE)
  8. 。建てる();
  9. mathGameIntent.setOperation(operationMath);
  10. 開始Ability(mathGameIntent);
  11. }

これまで、幼児向けの算数の問題と教育用ジグソーパズルの 2 つのページにジャンプしました。

  • 幼児向けの算数の質問を設定するロジックは、setQuestion と checkAnswer の 2 つのメソッドを参照できます。
  • ジグソーパズルゲームの絵のシャッフル順、絵の移動、ゲーム終了の判定、再開については、それぞれ pictureRandom、moveFun、gameOverFun、restartFun 関連のメソッドを参照してください。

スペースが限られていることと、関連するゲーム アルゴリズムがこのコードラボで重点的に扱いたい HarmonyOS 機能の一部ではないことから、ここでは詳細には触れません。関連する関数を呼び出し、関連するコードを理解して、ゲーム機能を実装できます。添付のコードにも詳細なコメントが記載されています。以上でHarmonyOSアプリケーションのスタンドアロン版の開発は完了です。次に、HarmonyOS の分散機能に基づいた関連システム設計の紹介に焦点を当てます。

5. デバイスを検出し、接続を確立する

幼児の算数問題のリアルタイム指導をクリックするか、パズルゲームでの親子の協力をクリックすると、下の図に示すように、デバイス選択ページがポップアップ表示されます。デバイス選択ダイアログをデバイス ディレクトリにパッケージ化しました。具体的なコードについては、DevicesListAdapter (デバイス リスト アダプター)、item_device_list.xml (デバイス リスト アイテム レイアウト)、SelectDeviceDialog (デバイス リストを選択するためのポップアップ ウィンドウ)、dialog_select_device.xml (ポップアップ ウィンドウ レイアウト) を参照してください。

SelectDeviceDialog のデバイス選択ポップアップ ウィンドウのコンストラクターは次のとおりです。コンテキスト、デバイス リスト、選択結果のコールバック イベントの 3 つのパラメータを渡す必要があります。ビジネス コードで次のコンストラクターを呼び出して、デバイスを選択するためのポップアップ ウィンドウを開きます。コードは次のとおりです。

  1. パブリックSelectDeviceDialog(Contextコンテキスト、List<DeviceInfo>デバイス、SelectResultListenerリスナー) {
  2. initView(コンテキスト、デバイス、リスナー);
  3. }

リストデバイスは次の関数を通じて取得できます。コードは次のとおりです。

  1. プライベートvoid getDevices() {
  2. (デバイスサイズ() > 0)の場合{
  3. デバイスをクリアします。
  4. }
  5. リスト<デバイス情報> デバイス情報 =
  6. DeviceManager.getDeviceList(ohos.distributedschedule.interwork.DeviceInfo.FLAG_GET_ONLINE_DEVICE);
  7. LogUtil.info(TAG, "deviceInfosサイズは:" + deviceInfos.size ());
  8. デバイスにデバイス情報を追加します。
  9. デバイスダイアログを表示します。
  10. }

選択結果のコールバックイベントは、業務に応じて異なるコールバックイベントで渡すことができます。たとえば、幼児向けの算数の問題でデバイスを選択した後、ローカルとリモートの 2 つのキャンバスを表示する必要があります。サブスクリプション イベントは startLocalFa と startRemoteFa です。コードは次のとおりです。

  1. プライベートvoid showDevicesDialog() {
  2. 新しいSelectDeviceDialog(this, devices, deviceInfo -> {
  3. startLocalFa(デバイス情報を取得します。デバイスIDを取得します)
  4. startRemoteFa(デバイス情報.getDeviceId());
  5. })。見せる();
  6. }

パズル ゲームでは、別のデバイスのパズル ページを開くために、別のデバイスとの接続を確立する必要があります。コールバック イベントは connectRemotePa で、コードは次のとおりです。

  1. プライベートvoid showDevicesDialog() {
  2. 新しいSelectDeviceDialog(this, devices, deviceInfo -> {
  3. connectRemotePa(deviceInfo.getDeviceId(), PictureRemoteProxy.REQUEST_START_ABILITY);
  4. })。見せる();
  5. }

コールバック関数内の deviceInfo はクリックによって選択されたデバイス情報であり、具体的には SelectDeviceDialog の initView メソッドで実装されていることに注意してください。コードは次のとおりです。

  1. DevicesListAdapter devicesListAdapter = 新しい DevicesListAdapter(デバイス、コンテキスト);
  2. デバイスリストコンテナにアイテムプロバイダーを設定します。
  3. devicesListContainer.setItemClickedListener((listContainer, コンポーネント, 位置, l) -> {
  4. リスナー.callBack(デバイス.get(位置));
  5. 共通ダイアログを非表示にします。
  6. });

これまでに、マルチデバイス コラボレーションでデバイスを検出し、接続を確立するという重要な手順が完了しました。

例:

FA をリモートで起動するには、少なくとも 2 つのデバイスが同じ分散ネットワーク内にある必要があります。これは次の操作によって実現できます。

すべてのデバイスは同じネットワークに接続されています。

すべてのデバイスで同じ Huawei アカウントにログインします。

すべてのデバイスで、「設定 -> その他の接続 -> 複数デバイスのコラボレーション」をオンにします。

6. 幼児期の算数の問題

幼児向けの算数問題をクリックすると、システムがランダムに 2 桁の加算問題を表示します。リアルタイム指導をクリックすると、2 つのキャンバスが表示されます。ローカル側では黒の手書き文字を使用してドラフト計算を実行し、リモート側では赤の手書き文字を使用してリアルタイムのガイダンスを実行できます。操作手順は両端でリアルタイムに同期されます。効果は以下の図に示されています。次に、HarmonyOS の分散技術を使用して両端での同期描画を実現する方法について詳しく説明します。


ステップ1 - デバイスを選択する

詳細については、「5 デバイスの検出と接続の確立」を参照してください。

ステップ2 - 接続を確立する

クリックしてデバイスを選択すると、図面ページが表示されます。 onStart メソッドでは、デバイスを初期化して接続する関数 initAndConnectDevice が呼び出されます。リモート デバイスの remoteDeviceId は、intent パラメータを通じて取得され、connectRemotePa が呼び出されて接続されます。コードは次のとおりです。

  1. プライベート void initAndConnectDevice(インテントインテント) {
  2. // ページの初期化
  3. this.context = MathDrawRemSlice.this;
  4. 文字列 remoteDeviceId = intent.getStringParam(CommonData.KEY_REMOTE_DEVICEID);
  5. isLocal = intent.getBooleanParam(CommonData.KEY_IS_LOCAL, false );
  6. if (findComponentById(ResourceTable.Id_text_title) インスタンスのテキスト) {
  7. テキスト textTitle = (テキスト) findComponentById(ResourceTable.Id_text_title);
  8. textTitle.setText(isLocal ? "ローカル" : "リモート" );
  9. }
  10.   
  11. // リモートサービスに接続
  12. リモートデバイスIDが空の場合(){
  13. リモートデバイスIDを接続します。
  14. }それ以外{
  15. LogUtil.info(TAG, "localDeviceId は null です" );
  16. }
  17. }

connectRemotePa メソッドを呼び出すと、MathGameServiceAbility とのサービス接続が確立されます。コードは次のとおりです。

  1. インテント connectPaIntent = 新しい Intent();
  2. 操作 operation = new Intent.OperationBuilder()
  3. .withDeviceId(デバイスID)
  4. .withBundleName(バンドル名を取得())
  5. .withAbilityName(CommonData.MATH_GAME_SERVICE_NAME)
  6. .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
  7. 。建てる();
  8. connectPaIntent.setOperation(操作);

接続が成功すると、onAbilityConnectDone メソッドがコールバックされ、2 つのデバイスが接続されます。次に、senDataToRemote メソッドを呼び出してデータを送信できます。コードは次のとおりです。

  1. パブリックvoid onAbilityConnectDone(ElementName 要素名、IRemoteObject リモート、 int結果コード) {
  2. LogUtil.info(タグ、 "onAbilityConnectDone..." );
  3. 接続能力(要素名、リモート、リクエストタイプ);
  4. }
  5.    
  6. プライベート void connectAbility(ElementName elementName, IRemoteObject remote, int requestType) {
  7. プロキシ = 新しい PictureRemoteProxy(リモート);
  8. LogUtil.error(TAG, "connectRemoteAbility が完了しました" );
  9. プロキシがnull場合
  10. 試す {
  11. proxy.senDataToRemote(リクエストタイプ);
  12. } キャッチ (RemoteException e) {
  13. LogUtil.error(タグ、 「onAbilityConnectDone RemoteException」 );
  14. }
  15. }
  16. }

ステップ3 - 描画操作(具体的な業務、送信データの準備)

DrawPoint は描画ツール クラスです。点を描画するときに、X軸の座標、Y軸の座標、最後の点かどうかの3つの情報を記録します。この情報はpointsX、pointsY、isLastPointArray配列に記録され、リストとしてカプセル化されます。 allPoints のデータ型は次のように定義されます。

  1. プライベートfloat [] pointsX;
  2. プライベートfloat [] pointsY;
  3. プライベートboolean[] isLastPointArray;
  4. プライベートList<MyPoint> allPoints = 新しいArrayList<>();

最後のポイントかどうかは、TouchEvent.PRIMARY_POINT_UP イベントによって区別されます。イベントが検出されると、コールバック関数 callBack.callBack(allPoints) が呼び出されます。コードは次のとおりです。

  1. touchEvent.getAction() が TouchEvent.PRIMARY_POINT_UP の場合 {
  2. point.setLastPoint( true );
  3. allPoints.add (ポイント);
  4. callBack.callBack(allPoints);
  5. }

このとき、setOnDrawBack メソッドがコールバックされ、コードは次のようになります。

  1. パブリックvoid setOnDrawBack(OnDrawCallBack コールバック) {
  2. this.callBack = コールバック;
  3. }

MathDrawRemSlice では、initDraw() がキャンバスを初期化します。描画が完了すると、setOnDrawBack メソッドがコールバックされます。 Points は上記の手順で描画された点であり、pointsX、pointsY、isLastPointArray 配列に格納されます。コードは次のとおりです。

  1. drawl.setOnDrawBack(ポイント -> {
  2. ポイントがnullの場合、ポイントのサイズは1 より大きいです。
  3. pointsX = 新しいfloat [points.サイズ()];
  4. pointsY = 新しいfloat [points.サイズ()];
  5. isLastPoint = 新しいブール値[ポイント。サイズ()];
  6. ( int i = 0; i < ポイント.サイズ(); i++) {
  7. pointsX[i] = points.get(i).getPositionX();
  8. pointsY[i] = points.get(i).getPositionY();
  9. ポイントを取得するには、ポイントの取得メソッドを使用します。
  10. }
  11. ...
  12. }
  13. });

この時点で、ローカル キャンバスの描画が完了し、描画されたポイントの情報が pointsX、pointsY、isLastPointArray 配列に格納され、送信するデータが準備できたことになります。

ステップ4 - データの送信

データの送信には、サービス能力、分散タスク スケジューリング、パブリック イベントという 3 つの HarmonyOS 機能が関係します。関連する基礎知識に精通していない場合は、まず公式ドキュメントを参照して学習することができます。描画が完了すると、senDataToRemote メソッドが呼び出され、描画されたポイント情報 (pointsX、pointsY、isLastPointArray) がデータに保存され、送信されます。コードは次のとおりです。

  1. プライベートvoid senDataToRemote( int requestType)はRemoteExceptionをスローします{
  2. LogUtil.info(TAG, "ローカル描画サービスにデータを送信します" );
  3. MessageParcel データ = MessageParcel.obtain();
  4. MessageParcel の返信 = MessageParcel.obtain();
  5. MessageOptionオプション= 新しい MessageOption(MessageOption.TF_SYNC);
  6. 試す {
  7. ポイントXがnullの場合、ポイントYがnullの場合、isLastPointがnull場合
  8. data.writeFloatArray(ポイントX);
  9. data.writeFloatArray(ポイントY);
  10. data.writeBooleanArray(最後のポイント)
  11. }
  12. remote.sendRequest(リクエストタイプ、データ、応答、オプション);
  13. ec を返信します
  14. (ec != ERR_OK)の場合{
  15. LogUtil.error(タグ、 「リモート例外:」 );
  16. }
  17. } キャッチ (RemoteException e) {
  18. LogUtil.error(タグ、 「リモート例外:」 );
  19. ついに
  20. データを再要求します。
  21. 返信.reclaim();
  22. }
  23. }

このうち、remote.sendRequest は MathGameServiceAbility のサービスにデータを送信します (ステップ 2 は MathGameServiceAbility とのサービス接続を確立するためです)。サービス接続が確立されると、onRemoteRequest メソッドがコールバックされます。コードは次のとおりです。

  1. @オーバーライド
  2. public boolean onRemoteRequest( intコード、MessageParcel データ、MessageParcel 応答、MessageOptionオプション) {
  3. LogUtil.info(タグ、 "onRemoteRequest..." );
  4. float [] pointsX = data.readFloatArray();
  5. float [] pointsY = data.readFloatArray();
  6. ブール値[] isLastPointArray = data.readBooleanArray();
  7. reply.writeInt(ERR_OK);
  8. sendEvent(isLastPointArray、pointsX、pointsY);
  9. 戻る 真実;
  10. }

onRemoteRequest メソッドでは、sendEvent が呼び出され、配列 pointsX、pointsY、isLastPointArray が送信されます。 sendEvent はパブリック イベントを通じてデータを転送します。登録されているパブリック イベントは CommonData.MATH_DRAW_EVENT です。コードは次のとおりです。

  1. プライベートvoid sendEvent(boolean[] isLastPoint, float [] pointsX, float [] pointsY) {
  2. LogUtil.info(TAG, "sendEvent..." );
  3. 試す {
  4. インテントのintent = 新しいIntent();
  5. 操作 operation = new Intent.OperationBuilder()
  6. .withAction(CommonData.MATH_DRAW_EVENT)
  7. 。建てる();
  8. インテントをsetOperation(操作);
  9. パラメータをintent.setParam(CommonData.KEY_POINT_X, pointsX);
  10. パラメータをintent.setParam(CommonData.KEY_POINT_Y, pointsY);
  11. パラメータをセットします。
  12. CommonEventData イベントデータ = 新しい CommonEventData(intent);
  13. CommonEventManager.publishCommonEvent(イベントデータ)。
  14. } キャッチ (RemoteException e) {
  15. LogUtil.error(TAG, "publishCommonEvent 例外が発生しました。" );
  16. }
  17. }

ステップ5 - データの受信

MathDrawRemSlice は CommonData.MATH_DRAW_EVENT のパブリック イベントをサブスクライブします。コードは次のとおりです。

  1. プライベートvoid subscribe() {
  2. マッチングスキル matchingSkills = new MatchingSkills();
  3. マッチングスキル。イベントを追加します(CommonData.MATH_DRAW_EVENT);
  4. マッチングスキル。イベントを追加します(CommonEventSupport.COMMON_EVENT_SCREEN_ON);
  5. CommonEventSubscribeInfo subscribeInfo = 新しい CommonEventSubscribeInfo(matchingSkills);
  6. サブスクライバー = 新しい MyCommonEventSubscriber(subscribeInfo);
  7. 試す {
  8. CommonEventManager.subscribeCommonEvent(サブスクライバー);
  9. } キャッチ (RemoteException e) {
  10. LogUtil.error( "" , "subscribeCommonEvent例外が発生しました。" );
  11. }
  12. }

関連するイベントがサブスクライブされると、onReceiveEvent メソッドがコールバックされます。このとき、pointsX、pointsY、isLastPointArray を解析し、drawl.setDrawParams(isLastPointArray, pointsX, pointsY) メソッドを呼び出してリモート側で描画します。コードは次のとおりです。

  1. パブリックvoid onReceiveEvent(CommonEventData commonEventData) {
  2. インテント intent = commonEventData.getIntent();
  3. ポイントX = intent.getFloatArrayParam(CommonData.KEY_POINT_X);
  4. ポイントY = intent.getFloatArrayParam(CommonData.KEY_POINT_Y);
  5. isLastPoint = intent.getBooleanArrayParam(CommonData.KEY_IS_LAST_POINT);
  6. // データを受信したら、リモートキャンバスを描画します
  7. drawl.setDrawParams(isLastPoint、pointsX、pointsY);
  8. LogUtil.info(タグ、 "onReceiveEvent...." );
  9. }

ステップ6 - データの双方向通信

手順 1 ~ 5 では、データの一方向通信、つまりローカル エンドからリモート エンドへのやり取りについて説明します。この例の描画は双方向通信であり、両端で描画できます。これはどのように達成されるのでしょうか?ステップ 1 でデバイスが選択されると、startLocalFa と startRemoteFa が呼び出され、startLocalFa によって渡される remoteDeviceId は選択されたデバイス ID であり、startRemoteFa によって渡される remoteDeviceId は現在のデバイスの ID であるため、双方向通信が実現されます。コードは次のとおりです。

  1. プライベートvoid showDevicesDialog() {
  2. 新しいSelectDeviceDialog(this, devices, deviceInfo -> {
  3. startLocalFa(デバイス情報を取得します。デバイスIDを取得します)
  4. startRemoteFa(デバイス情報.getDeviceId());
  5. })。見せる();
  6. }
  7. プライベートvoid startLocalFa(文字列デバイスID) {
  8. LogUtil.info(タグ、 "startLocalFa..." );
  9. インテントのintent = 新しいIntent();
  10. パラメータをセットします。
  11. ...
  12. }
  13. プライベートvoid startRemoteFa(文字列デバイスID) {
  14. LogUtil.info(TAG, "startRemoteFa..." );
  15. 文字列 localDeviceId = KvManagerFactory.getInstance()
  16. .createKvManager(新しい KvManagerConfig(this)).getLocalDeviceInfo().getId();
  17. インテントのintent = 新しいIntent();
  18. ローカルデバイスIDを設定します。
  19. ...
  20. }

デバイスの選択、接続の確立、データの送信、データの受信という重要な手順に従うことで、2 つのデバイスの同期描画とリアルタイム表示の機能を実現できます。

- 仕上げる

7. ジグソーパズル

ジグソーパズルゲームをクリックすると、9 マスのジグソーパズルゲームが表示され (画像はランダムに配置されます)、画像をクリックするとパズルが完成します。ローカル側で親子コラボレーションをクリックすると、リモート側に同一のゲーム ページが表示されます。 2 つのデバイスはリアルタイムで相互作用し、写真を同期してつなぎ合わせることができ、操作手順もリアルタイムで同期できます。効果図を以下に示します。次に、HarmonyOSの分散技術を使ってパズルゲームを実装する方法を詳しく紹介します。


ステップ1 - デバイスを選択する

詳細については、「5 デバイスの検出と接続の確立」のセクションを参照してください。

ステップ2 - 接続を確立し、デバイスを起動する

親子連携をクリックすると、選択したデバイスの deviceId が記録されます。 connectRemotePa メソッドを呼び出すと、フラグ ビットが REQUEST_START_ABILITY である PictureGameServiceAbility とのサービス接続が確立されます。コードは次のとおりです。

  1. プライベートvoid showDevicesDialog() {
  2. 新しいSelectDeviceDialog(this, devices, deviceInfo -> {
  3. connectRemotePa(deviceInfo.getDeviceId(), PictureRemoteProxy.REQUEST_START_ABILITY);
  4. })。見せる();
  5. }
  6. プライベートvoid connectRemotePa(String deviceId, int requestType) {
  7. デバイスIDが空の場合(){
  8. インテント connectPaIntent = 新しい Intent();
  9. 操作 operation = new Intent.OperationBuilder()
  10. .withDeviceId(デバイスID)
  11. .withBundleName(バンドル名を取得())
  12. .withAbilityName(CommonData.PICTURE_GAME_SERVICE_NAME)
  13. .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
  14. 。建てる();
  15. connectPaIntent.setOperation(操作);
  16. ...
  17. }

接続が成功すると、onAbilityConnectDone メソッドがコールバックされ、2 つのデバイスが接続されます。次に、sendDataToRemote メソッドを呼び出してデータを送信します。ここで、requestType は REQUEST_START_ABILITY です。コードは次のとおりです。

  1. パブリックvoid onAbilityConnectDone(ElementName 要素名、IRemoteObject リモート、 int結果コード) {
  2. LogUtil.info(タグ、 "onAbilityConnectDone..." );
  3. 接続能力(要素名、リモート、リクエストタイプ);
  4. }
  5.    
  6. プライベート void connectAbility(ElementName elementName, IRemoteObject remote, int requestType) {
  7. プロキシ = 新しい PictureRemoteProxy(リモート);
  8. LogUtil.error(TAG, "connectRemoteAbility が完了しました" );
  9. プロキシがnull場合
  10. 試す {
  11. proxy.sendDataToRemote(リクエストタイプ);
  12. } キャッチ (RemoteException e) {
  13. LogUtil.error(タグ、 「onAbilityConnectDone RemoteException」 );
  14. }
  15. }
  16. }

PictureGameServiceAbility サービスで senDataToRemote メッセージを受信すると、onRemoteRequest がコールバックされます。このときコードは REQUEST_START_ABILITY なので、リモート側のパズルページが表示されます。コードは次のとおりです。

  1. public boolean onRemoteRequest( intコード、MessageParcel データ、MessageParcel 応答、MessageOptionオプション) {
  2. ...
  3. if (コード == REQUEST_START_ABILITY) {
  4. LogUtil.error(TAG, "RemoteServiceAbility::isFirstStart:" );
  5. インテント secondIntent = new Intent();
  6. 操作 operation = new Intent.OperationBuilder().withDeviceId( "" )
  7. .withBundleName(バンドル名を取得())
  8. .withAbilityName(CommonData.ABILITY_MAIN)
  9. .withAction(CommonData.PICTURE_PAGE)
  10. 。建てる();
  11. ...
  12. }それ以外{
  13. ...
  14. }
  15. ...
  16. }

以上で、ローカル側からリモート側への一方向通信が完了します。リモートデバイスが起動すると、PictureGameAbilitySlice で onStart メソッドが実行され、次に initRemoteView メソッドが実行され、その中で connectRemotePa メソッドが再度呼び出されます。このとき渡されるフラグは REQUEST_SEND_DATA です。ローカルデバイスのページは繰り返し起動されず、データ接続のみが確立されます。コードは次のとおりです。

  1. プライベートvoid initRemoteView(インテントインテント) {
  2. ローカルの場合
  3. リモートデバイスID = intent.getStringParam(CommonData.KEY_REMOTE_DEVICEID);
  4. リモートデバイス ID を接続します。
  5. 画像インデックスがnull場合
  6. データ情報を更新します。
  7. }
  8. }
  9. }

上記の手順により、ローカル側とリモート側の間の双方向通信が完了し、データ転送機能が実現されます。

ステップ3 - ジグソー操作(特定の業務、送信するデータの準備)

スペースが限られていることと、ジグソーパズル ゲームはこのコードラボで紹介したい HarmonyOS の機能の 1 つではないため、詳細には触れません。ご自身で理解してください。私たちがお伝えする結論は、パズル操作を完了するには、移動した画像の添え字 moveImageId、移動した画像の位置 movePosition、および最終配置された画像の添え字 imageIndex という 3 つの重要なデータを記録する必要があるということです。パズルを1回クリックすると、上記の3つのデータが記録されます。コードは次のとおりです。

  1. プライベートクラス ImageClick は Component.ClickedListener を実装します {
  2. @オーバーライド
  3. パブリックvoid onClick(コンポーネント コンポーネント) {
  4. int imageId = コンポーネント.getId();
  5. ( int position = 0; position < imageIndex.length; position++) {
  6. if (imageId == imageResourceTable[位置]) {
  7. // 画像の動きを完了し、動きの情報を記録する
  8. moveFun(画像ID、位置);
  9. イメージIDを移動します。
  10. 位置を移動します。
  11. }
  12. }
  13. // ページの表示を更新します
  14. 画像インデックスにイメージとデコード境界を設定します。
  15. // データを送信する
  16. senDataToRemoteFun();
  17. }
  18. }

ステップ4 - データの送信

データを送信するプロセスは、幼児の算数の問題と同じです。詳しくはまた改めてご紹介させていただきます。比較研究のために幼児期の算数の問題を参照することができます。パズルが完了すると、senDataToRemote メソッドが呼び出され、キー情報 (imageIndex、moveImageId、movePosition) がデータに保存され、送信されます。コードは次のとおりです。

  1. プライベートvoid senDataToRemote( int requestType)はRemoteExceptionをスローします{
  2. MessageParcel データ = MessageParcel.obtain();
  3. ...
  4. 試す {
  5. ...
  6. data.writeIntArray(画像インデックス);
  7. data.writeInt(画像IDを移動)
  8. data.writeInt(位置を移動)
  9. remote.sendRequest(リクエストタイプ、データ、応答、オプション);
  10. ...
  11. } キャッチ (RemoteException e) {
  12. ...
  13. ついに
  14. ...
  15. }
  16. }

このうち、remote.sendRequest は PictureGameServiceAbility サービスにデータを送信し (ステップ 2 は PictureGameServiceAbility とのサービス接続を確立するため)、サービス接続が確立された後に onRemoteRequest メソッドがコールバックされます。受信順序は送信順序 (imageIndex、moveImageId、movePosition) と一致している必要があります。一致していないと、受信操作が間違ってしまいます。コードは次のとおりです。

  1. public boolean onRemoteRequest( intコード、MessageParcel データ、MessageParcel 応答、MessageOptionオプション) {
  2. LogUtil.info(タグ、 "onRemoteRequest..." );
  3. int [] imageIndex = data.readIntArray();
  4. int移動イメージ ID = data.readInt();
  5. int移動位置 = data.readInt();
  6. ...
  7. LogUtil.info(TAG, "受信番号:" + imageIndex.length);
  8. reply.writeInt(ERR_OK);
  9. if (コード == REQUEST_START_ABILITY) {
  10. ...
  11. }それ以外{
  12. sendEvent(画像インデックス、画像ID、位置の移動);
  13. }
  14. 戻る 真実;
  15. }

onRemoteRequest メソッドでは、sendEvent が呼び出され、imageIndex、moveImageId、movePosition が送信されます。 sendEvent は共通イベントを登録してデータを転送します。登録された共通イベントは CommonData です。ピクチャー_ゲーム_イベント。コードは次のとおりです。

  1. プライベートvoid sendEvent( int [] imageIndex, int moveImageId, int movePosition) {
  2. 試す {
  3. インテントのintent = 新しいIntent();
  4. 操作 operation = new Intent.OperationBuilder()
  5. .withAction(CommonData.PICTURE_GAME_EVENT)
  6. 。建てる();
  7. インテントをsetOperation(操作);
  8. パラメータをセットします。
  9. パラメータをセットします。
  10. intent.setParam(CommonData.KEY_MOVE_POSITION、movePosition);
  11. CommonEventData イベントデータ = 新しい CommonEventData(intent);
  12. CommonEventManager.publishCommonEvent(イベントデータ)。
  13. } キャッチ (RemoteException e) {
  14. LogUtil.error(TAG, "publishCommonEvent 例外が発生しました。" );
  15. }
  16. }

ステップ5 - データの受信

データを受信するコードフローは、幼児向け算数の問題と同じです。詳しくはまた改めてご紹介させていただきます。比較研究のために幼児期の算数の問題を参照することができます。 PictureGameAbilitySlice は CommonData のパブリック イベントをサブスクライブします。ピクチャー_ゲーム_イベント。コードは次のとおりです。

  1. プライベートvoid subscribe() {
  2. マッチングスキル matchingSkills = new MatchingSkills();
  3. マッチングスキルにイベントを追加します(CommonData.PICTURE_GAME_EVENT);
  4. マッチングスキル。イベントを追加します(CommonEventSupport.COMMON_EVENT_SCREEN_ON);
  5. CommonEventSubscribeInfo subscribeInfo = 新しい CommonEventSubscribeInfo(matchingSkills);
  6. サブスクライバー = 新しい MyCommonEventSubscriber(subscribeInfo);
  7. 試す {
  8. CommonEventManager.subscribeCommonEvent(サブスクライバー);
  9. } キャッチ (RemoteException e) {
  10. LogUtil.error( "" , "subscribeCommonEvent例外が発生しました。" );
  11. }
  12. }

関連するイベントがサブスクライブされると、onReceiveEvent メソッドがコールバックされます。このとき、imageIndex、moveImageId、movePosition を解析することができ、updateDataInfo が呼び出されて相手側のレイアウト ファイルが更新されます。コードは次のとおりです。

  1. @オーバーライド
  2. パブリックvoid onReceiveEvent(CommonEventData commonEventData) {
  3. ...
  4. インテント intent = commonEventData.getIntent();
  5. データ情報を更新します。
  6. }
  7.    
  8. プライベート void updateDataInfo(インテントインテント) {
  9. 画像インデックス = intent.getIntArrayParam(CommonData.KEY_IMAGE_INDEX);
  10. 移動イメージID = intent.getIntParam(CommonData.KEY_MOVE_IMAGE_ID, -1);
  11. 移動位置 = intent.getIntParam(CommonData.KEY_MOVE_POSITION, -1);
  12. getUITaskDispatcher().delayDispatch(() -> setImageAndDecodeBounds(imageIndex), DELAY_TIME);
  13. }

デバイスの選択、接続の確立、データの送信、データの受信という重要な手順に従うことで、2 つのデバイス間で同期されたパズルの機能を実現できます。上記の 2 つのケースでは、2 つのデバイス間のデータのやり取りを十分に理解し、HarmonyOS の分散特性を体験しました。何か得られると信じています。

- 仕上げる

例:

上記のコードはデモの参考用です。製品コードでは、データの検証と国際化を考慮する必要があります。

8. 総括と結論

このコードラボでは、親子の早期教育システムを使用して、早期教育の算数問題と教育用ジグソーパズルという 2 つの包括的なケースを徹底的に紹介します。 HarmonyOS アプリケーション開発、マルチスクリーンインタラクション、分散型クロスデバイスコラボレーションの機能をすぐに理解できるようにすることを目的としています。デバイス間のコラボレーション、分散タスクのスケジュール設定、パブリック イベントという 3 つの HarmonyOS 機能を習得することに重点を置く必要があります。特に、分解手順を通じて 2 つのデバイス間でデータを転送する方法を詳しく紹介します。これは、学習と習得に重点を置く必要がある知識ポイントです。

さらに、このコードラボの 2 つのケースでは、分散データ サービスと分散ファイル サービスを通じてコードを最適化することもできます。この点に関する知識ポイントと事例については、今後のコードラボで紹介していきます。

9.おめでとうございます

  • これでコードラボは正常に完了し、次の内容を学習しました。
  • 共通レイアウトとカスタムコントロールの使用
  • ページ能力、サービス能力、意図
  • マルチスクリーンインタラクション、分散型クロスデバイスコラボレーション、分散型タスクスケジューリング
  • 公開イベント

10. 参考文献

gitee ソースコード

github ソースコード

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

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

https://harmonyos..com

<<:  エコパートナーが100社を超えました! Tencent Meeting RoomsがMac、Windows、Androidプラットフォームに対応

>>:  エッジツークラウドコンピューティングアーキテクチャがデジタルイニシアティブの鍵となる

推薦する

#USA VPS# wishosting-OpenNebula Cloud/$3.99/KVM/2g メモリ/ロサンゼルス

wishosting.com には、KVM 仮想化に基づく安価な VPS がいくつかあります。価格が...

QQスペースを使って年間数百万ドルを稼ぐ方法

今日、「投稿で年間数百万ドルを稼ぐ方法」という記事を見ました。主に、煮込み料理店を経営する社長が、天...

インターネット金融業務入門ガイド!

インターネット時代において、伝統的な金融機関とインターネット企業は、インターネット技術と情報通信技術...

WeChatは「四方八方から待ち伏せ」されており、ソーシャルトラックは簡単には諦めないだろう!

2016年初頭、28歳の張連安さんはWeChatのエンジニアの仕事を辞め、すぐに新しいソーシャルプロ...

Python プログラミング言語クイック スタート チュートリアル

この記事は、SEO 担当者向けの Python プログラミング言語の入門チュートリアルです。プログラ...

短期間でウェブサイト数を急速に増やす方法の簡単な分析

ロングテールキーワードは、他の最適化方法に比べて競争が少なく、ターゲットがより正確で、コンバージョン...

タグ: ソーシャル ネットワーキング サイト、見つけやすい、分析

大手ソーシャル ネットワーキング サイトと比較すると、Yixun は小規模で新興のソーシャル ネット...

百度のアルゴリズムは誰が一番悲しいかを調整している

ここ数日は、多くの新旧ウェブマスターにとって非常に困難な日々でした。多くの人が、Baidu は人々の...

ウェブサイトのランキングを上げる鍵は、最適化のボトルネックを打破することです

SEO最適化を行うスタッフが最も望んでいるのは、ウェブサイトのランキングが継続的に上昇することです。...

ウェブサイト分析ハック: オンライン決済プロセスの最適化

この記事は、Web 分析の第一人者である Eric T. Peterson 氏の著書「Web Sit...

drServer-3.5 EUR/Windows/1G RAM/20g SSD/1T トラフィック

2006 年に設立された drServer には、いくつかのサブブランドがあり、その 1 つが vi...

クレイジーストーン:中国初のオンラインローン詐欺事件、7億元が関与

[概要] この違法取引所は、翡翠資産パッケージを通じて株式取引を行い、投資家の預金を吸収して市場を操...

Webmaster Revolution が Weibo マーケティングにリンク

多くのウェブマスターは、ウェブサイトを作成した後、自分のウェブサイトの重みを改善する方法を探していま...

トラフィックを爆発的に増やすためにウェブサイトをうまく運営する方法

ウェブサイトの運用はウェブマスターにとって大きな課題であり、運用結果の品質はウェブサイトの価値に直接...