假设您有一个跨平台应用程序。该应用程序运行在安卓和iOS上。跨两个平台的共享语言是Java。通常,您将用Java编写业务逻辑,用Java (用于Android)和Objective(用于iOS)编写所有UI特定部分。
通常,当您在跨平台、跨语言应用程序中实现MVP模式时,您将使用Java和演示者,并为您的视图提供一个Java接口,这是您的演示人员所知道的。这样,您的共享Java演示程序就可以与平台特定部分上使用的任何视图实现进行通信。
让我们假设我们想要编写一个iOS应用程序,其中包含一个Java部件,稍后可以与同一个安卓应用程序共享。下面是设计的图形表示:

在左侧是Java部分。用Java编写模型、控制器和视图接口。使用依赖注入完成所有布线。然后可以使用J2objc将Java代码转换为Objective。
在右边,你有目标C部分。在这里,您的UIViewController可以实现ObjectiveC接口,这些接口被转换成ObjectiveC协议。
问题:
我正在挣扎的是视图之间的导航是如何发生的。假设您在UIViewControllerA上,然后点击一个按钮,该按钮将带您进入UIViewControllerB。你怎么做?
案例1:

您可以将按钮点击到UIViewControllerA的Java UIViewControllerA (1),Java ControllerA调用连接到UIViewControllerB (3)的UIViewControllerB (2)。然后,您有一个问题,您不知道UIViewControllerB如何在Objective视图层次结构中插入UIViewControllerB。您无法从Java端处理这个问题,因为您只能访问View接口。
案例2:

您可以进行到UIViewControllerB的转换,无论它是模态的,还是使用UINavigationController或其他什么的(1)。然后,首先需要正确的UIViewControllerB实例,该实例绑定到ControllerB (2)。否则,UIViewControllerB无法交互ControllerB (2,3)。当您拥有正确的实例时,您需要告诉Java ControllerB视图(UIViewControllerB)已经显示。
我仍然在努力解决如何处理不同控制器之间的导航问题。
如何对不同控制器之间的导航建模并适当地处理跨平台视图的更改?
发布于 2015-05-23 11:50:30
我建议你使用某种插槽机制。类似于其他MVP框架使用的内容。
定义:插槽是可以插入其他视图的视图的一部分。
在演示者中,您可以定义任意数量的插槽:
GenericSlot slot1 = new GenericSlot();
GenericSlot slot2 = new GenericSlot();
GenericSlot slot3 = new GenericSlot();在推荐人看来,这些插槽必须有一个参考。您可以实现
setInSlot(Object slot, View v);方法。如果您在视图中实现了setInSlot,那么视图可以决定如何包含它。
看看插槽是如何实现这里的。
发布于 2015-05-19 18:28:23
简短答覆:
我们是这样做的:
Activity/UIViewController,而不需要任何逻辑)-- ActivityA直接打开ActivityB。如果需要,ActivityB现在负责与应用程序共享逻辑层进行通信。ActivityA调用某个UseCase的方法,该方法返回一个enum或public static final int,并相应地采取一些操作- or -UseCase可以调用我们之前注册的ScreenHandler的方法,它知道如何在应用程序中的任何地方使用一些提供的参数打开公共Activities。
较长的答覆:
我是一家公司的首席开发人员,该公司为应用程序的模型、逻辑和业务规则使用java库,移动平台(Android )都使用j2objc实现了这些规则。
我的设计原则直接来自Bob叔叔和SOLID,我真的不喜欢在设计完整的应用程序时使用MVP或MVC来完成组件间的通信,因为然后您就开始将每个Activity与1 Controller连接起来,这有时是可以的,但大多数情况下,您最终会得到一个控制器的上帝对象,该对象的变化往往与View一样大。这可能导致严重的代码气味。
我最喜欢的处理方法(也是我发现的最干净的方法)是把所有的东西都分解成UseCases,每个处理应用程序中的1“情况”。当然,您可以拥有一个Controller来处理这些UseCases中的几个,但是它所知道的只是如何委托给这些UseCases,仅此而已。
此外,我认为没有理由将Activity的每个操作链接到逻辑层中的Controller,如果此操作是一个简单的“带我到地图屏幕”或任何类似的操作。Activity的角色应该是处理它所持有的Views,并且作为应用程序生命周期中唯一的“智能”事物,我认为它没有理由不能调用下一个活动本身的开始。
此外,Activity/UIViewController生命周期太复杂,彼此之间太不一样,无法由普通的java库来处理。我认为这是一个“细节”,而不是真正的“业务规则”,每个平台都需要实现和担心,从而使java中的代码更加坚实,不容易更改。
同样,我的目标是使应用程序的每个组件都尽可能地成为SRP (单一责任原则),这意味着将尽可能少的东西连接在一起。
所以一个简单的“正常”东西的例子:
(所有的例子都是虚构的)
ActivityAllUsers显示模型对象项的列表。这些项来自调用AllUsersInteractor --后台线程中的一个UseCase controller(这反过来也由java处理,在请求完成时,它将调度到主线程)。用户单击此列表中的项目之一。在这个例子中,ActivityAllUsers已经有了模型对象,所以打开ActivityUserDetail是一个简单的调用,它包含这个数据模型对象的一个包(或另一种机制)。如果需要进一步的操作,新的活动ActivityUserDetail负责创建和使用正确的UseCases。
复杂逻辑调用的示例:
ActivityUserDetail有一个名为“添加为朋友”的按钮,当单击该按钮时,该按钮在ActivityUserDetail中调用回调方法onAddFriendClicked。
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;
}
}更复杂的调用示例
安卓上的BroadcastReceiver或iOS上的AppDelegate都会收到推送通知。这将被发送到NotificationHandler,它位于java逻辑层。在NotificationHandler构造函数(只在App.onCreate()中构造一次)中,它需要在两个平台上实现的ScreenHandler interface。解析此推送通知,并在ScreenHandler中调用正确的方法来打开正确的Activity。
底线是:尽可能保持View的愚蠢,让Activity足够聪明地处理自己的生命周期和处理自己的视图,并与自己的controllers (复数!)通信,其他的一切都应该在java库中编写(希望是测试优先;)。
使用这些方法,我们的应用程序目前在java库中运行了大约60%-70%的代码,下一次更新将有望使其达到70-80%。
发布于 2015-05-19 21:54:52
在跨平台开发共享(我称之为“核心”(用Java编写的应用程序的域)中,我倾向于让UI拥有下一个要显示的视图。这使得您的应用程序更加灵活,可以根据需要适应环境(在iOS上使用UINavigationController,在Android上使用片段,在web界面上使用带有动态内容的单个页面)。
您的controllers不应该绑定到视图,而是履行特定的角色(用于登录/注销的accountController,用于显示和编辑菜谱的recipeController等等)。
您将使用interfaces作为controllers,而不是views。然后您可以使用工厂设计模式在域端(您的controllers代码)实例化您的controllers,并在UI端实例化views。view factory对域的controller factory有一个引用,并使用它向请求的视图提供一些实现特定接口的控制器。

示例:在点击“登录”按钮后,homeViewController向ViewControllerFactory请求一个loginViewController。该工厂反过来要求ControllerFactory提供一个实现accountHandling接口的控制器。然后,它实例化一个新的loginViewController,给出它刚刚收到的控制器,并将新实例化的视图控制器返回给homeViewController。然后,homeViewController将新的视图控制器呈现给用户。
因为您的“核心”与环境无关,并且只包含您的域和业务逻辑,所以它应该保持稳定,并且不太容易编辑。
您可以看看我做的这个简化的演示项目,它说明了这个设置(减去接口)。
https://stackoverflow.com/questions/30267401
复制相似问题