13

クロス プラットフォーム アプリケーションがあるとします。アプリケーションは、Android と iOS で実行されます。両方のプラットフォームで共通の言語は Java です。通常、ビジネス ロジックは Java で記述し、UI 固有の部分はすべて Java (Android の場合) と Objective-C (iOS の場合) で記述します。

通常、クロス プラットフォーム、クロス言語アプリケーションでMVP パターンを実装する場合、Java でモデルとプレゼンターを持ち、プレゼンターに知られているビュー用の Java インターフェイスを提供します。このようにして、共有 Java プレゼンターは、プラットフォーム固有の部分で使用するビューの実装と通信できます。

後で同じ Android アプリと共有できる Java 部分を含む iOS アプリを作成するとします。設計のグラフィカルな表現は次のとおりです。

ここに画像の説明を入力

左側に Java 部分があります。Java では、モデル、コントローラー、およびビュー インターフェイスを記述します。依存性注入を使用してすべての配線を行います。その後、 J2objcを使用して Java コードを Objective-C に変換できます。

右側には、Objective-C の部分があります。ここでUIViewControllerは、ObjectiveC プロトコルに変換された Java インターフェイスを実装できます。

問題:

私が苦労しているのは、ビュー間のナビゲーションがどのように行われるかです。UIViewControllerA にいて、UIViewControllerB に移動するボタンをタップするとします。あなたならどうしますか?

ケース 1:

ここに画像の説明を入力

ボタンのタップを UIViewControllerA の Java ControllerA (1) に報告すると、Java ControllerA は UIViewControllerB (3) にリンクされている Java ControllerB (2) を呼び出します。次に、Objective-C ビュー階層に UIViewControllerB を挿入する方法を Java コントローラー側から知らないという問題があります。View インターフェースにしかアクセスできないため、Java 側からそれを処理することはできません。

ケース 2:

ここに画像の説明を入力

モーダルであるか、UINavigationController などを使用しているかにかかわらず、UIViewControllerB への移行を行うことができます (1)。次に、最初に、Java ControllerB にバインドされる UIViewControllerB の正しいインスタンスが必要です (2)。そうしないと、UIViewControllerB は Java ControllerB (2,3) と対話できませんでした。正しいインスタンスを取得したら、View (UIViewControllerB) が公開されたことを Java ControllerB に伝える必要があります。

異なるコントローラー間のナビゲーションをどのように処理するかというこの問題にまだ苦労しています。

異なるコントローラー間のナビゲーションをモデル化し、クロスプラットフォームのビューの変更を適切に処理するにはどうすればよいですか?

4

3 に答える 3

5

簡潔な答え:

その方法は次のとおりです。

  • 単純な「通常の」もの(デバイスのカメラを開くボタンや別のボタンを開くActivity/UIViewControllerアクションの背後にあるロジックなし)の場合-ActivityA直接 opens ActivityB. ActivityB必要に応じて、アプリ共有ロジック レイヤーとの通信を担当するようになりました。
  • より複雑なものやロジックに依存するものについては、2 つのオプションを使用しています。
    1. ActivityAorUseCaseを返すsome のメソッドを呼び出し、それに応じて何らかのアクションを実行します -OR-enumpublic static final int
    2. Saidは、提供されたパラメーターを使用して、アプリ内のどこからでもcommon を開く方法を知っている、以前に登録しUseCaseた のメソッドを呼び出すことができます。ScreenHandlerActivities

長い答え:

私は、両方のモバイル プラットフォーム (Android と iOS) が j2objc を使用して実装するアプリケーションのモデル、ロジック、およびビジネス ルールに Java ライブラリを使用する会社の主任開発者です。

私の設計原則は Uncle Bob と SOLID から直接来ています。コンポーネント間通信を備えたアプリケーション全体を設計するときに MVP や MVC を使用するのは本当に嫌いActivityですController。と同じくらい変化する傾向があるコントローラーの神のオブジェクトになりViewます。これにより、深刻なコードの臭いが発生する可能性があります。

UseCasesこれを処理する私のお気に入りの方法 (そして最もクリーンな方法) は、アプリ内の 1 つの「状況」を処理するそれぞれにすべてを分割することです。確かにController、それらのいくつかを処理する を持つことができますが、UseCasesそれが知っているのはそれらに委任する方法だけUseCasesです。

Activityさらに、このアクションが単純な「マップ画面に移動する」またはこの種のものである場合、のすべてのアクションを論理レイヤーにController座っていることにリンクする理由がわかりません。の役割は、それが保持Activityするものを処理するViewsことであり、アプリケーションのライフサイクルに存在する唯一の「スマート」なものとして、次のアクティビティ自体の開始を呼び出せない理由はないと思います。

さらに、Activity/UIViewControllerライフサイクルが複雑すぎて、共通の Java ライブラリで処理するには、それぞれがあまりにも異なっています。これは私が「詳細」と見なすものであり、実際には「ビジネス ルール」ではありません。各プラットフォームが実装して考慮する必要があるため、Java ライブラリのコードがより堅実になり、変更されにくくなります。

繰り返しになりますが、私の目標は、アプリの各コンポーネントを可能な限り SRP (Single Responsibility Principle) にすることです。これは、リンクするものをできるだけ少なくすることを意味します。

したがって、単純な「通常の」ものの例:

(すべての例は完全に架空のものです)

ActivityAllUsersモデル オブジェクト アイテムのリストを表示します。これらの項目は、バック スレッドで -a を呼び出しAllUsersInteractorUseCase controller作成されました (これは、要求が完了したときに、メイン スレッドへのディスパッチを伴う Java ライブラリによっても処理されます)。ユーザーは、このリスト内の項目の 1 つをクリックします。この例では、 はActivityAllUsersすでにモデル オブジェクトを持っているためActivityUserDetail、このデータ モデル オブジェクトのバンドル (または別のメカニズム) を使用して簡単に開くことができます。新しいアクティビティ は、さらにアクションが必要な場合ActivityUserDetailに正しい を作成して使用する責任があります。UseCases

複雑なロジック呼び出しの例:

ActivityUserDetail「友達として追加」というタイトルのボタンがあり、クリックすると次のコールバックメソッドが呼び出さonAddFriendClickedActivityUserDetailます。

public void onAddFriendClicked() {  
  AddUserFriendInteractor addUserFriend = new AddUserFriendInteractor();
  int result = addUserFriend.add(this.user);
  switch(result){
    case AddUserFriendInteractor.ADDED:
      start some animation or whatever
      break;
    case AddUserFriendInteractor.REMOVED:
      start some animation2 or whatever
      break;
    case AddUserFriendInteractor.ERROR:
      show a toast to the user
      break;
    case AddUserFriendInteractor.LOGIN_REQUIRED:
      start the log in screen with callback to here again
      break;

  }
}

さらに複雑な呼び出しの例

BroadcastReceiverAndroid またはAppDelegateiOSの Aは、プッシュ通知を受け取ります。NotificationHandlerこれは、java lib 論理層にあるものに送信されます。一度構築されたNotificationHandlerコンストラクターでは、両方のプラットフォームで実装した をApp.onCreate()受け取ります。ScreenHandler interfaceこのプッシュ通知が解析され、正しいメソッドが呼び出されてScreenHandler正しい が開きますActivity

肝心なのは:Viewをできるだけ馬鹿にしてActivity、自分のライフサイクルを処理し、自分のビューを処理し、自分自身と通信するのに十分なだけ賢く保ちますcontrollers(複数形!)、そして他のすべてを書く必要があります (できればテスト-最初 ;) ) Java ライブラリ内。

これらのメソッドを使用すると、アプリは現在、Java ライブラリ内のコードの約 60 ~ 70% を実行しています。次の更新では、うまくいけば 70 ~ 80% になるはずです。

于 2015-05-19T18:28:23.903 に答える
1

ある種のスロット機構を使用することをお勧めします。他の MVP フレームワークが使用するものと同様です。

定義: スロットは、他のビューを挿入できるビューの一部です。

プレゼンターでは、必要な数のスロットを定義できます。

GenericSlot slot1 = new GenericSlot();
GenericSlot slot2 = new GenericSlot();
GenericSlot slot3 = new GenericSlot();

これらのスロットには、プレゼンターのビューで参照が必要です。実装できます

setInSlot(Object slot, View v);

方法。ビューに実装する場合setInSlot、ビューはそれをどのように含めるかを決定できます。

ここでスロットがどのように実装されているかを見てください

于 2015-05-23T11:50:30.323 に答える