Android MVP模式包结构

我在Android上看到了MVP模式的各种很棒的教程,但作者似乎在封装上有不同的做法。

我看到的第一个教程通过function进行了装。 如“login”,“join”,“UI”包等。

UI包只有活动,“login”包具有演示者和具体演示者的接口,而此包包含一个子包“模型”,其中包含有关login模型(与服务器的通信)的所有内容。 “join”包与“login”包具有相同的组成。

但是我看到的另外一个包装是按照“join”,“login”等方式进行的。

“join”包包含一个活动,以及三个名为“模型”,“视图”,“演示者”的子包。

最佳做法是什么? 有没有处理这个问题的文章?

  • 如何使用适用于Android的MVP模式控制ListView
  • Android MVP从Presenter打开Activity,反模式?
  • Android MVP - 如何在活动演示者和片段演示者之间进行通信
  • 在Android中实现Model-View-Presenter的困难
  • MVP是View还是Presenter的onClick责任?
  • 如何在不使用Dagger的情况下使用MVP中的共享首选项并且不会导致Presenter与上下文相关?
  • 多个活动/片段和模型视图演示者模式
  • 在Android MVP中放置BroadcastReceiver的位置?
  • 我只是在这里重新发布我的答案

    我经常把业务逻辑代码放在模型层 (不要和数据库中的模型混淆)。 为了避免混淆,我经常将其重命名为XManager (如ProductManagerMediaManager …),因此演示者类仅用于保留工作stream。

    经验法则是没有或至less限制在演示者类中导入android包 。 这个最佳实践支持您更容易地testing演示者类,因为演示者现在只是一个普通的java类,所以我们不需要android框架来testing这些东西。

    例如这里是我的mvp工作stream程。

    视图类 :这是一个地方,你存储所有的视图,如button,文本视图…,你设置这个视图组件的这个层的所有侦听器。 同样在这个视图中,您稍后为演示者实现定义一个Listener类。 你的视图组件将调用这个监听器类的方法。

     class ViewImpl implements View { Button playButton; ViewListener listener; public ViewImpl(ViewListener listener) { // find all view this.listener = listener; playButton.setOnClickListener(new View.OnClickListener() { listener.playSong(); }); } public interface ViewListener { playSong(); } } 

    演示者类:这是您将视图和模型存储在其中以供稍后调用的位置。 另外主持人类将实现上面定义的ViewListener接口。 演示者的要点是控制逻辑工作stream程。

     class PresenterImpl extends Presenter implements ViewListener { private View view; private MediaManager mediaManager; public PresenterImpl(View, MediaManager manager) { this.view = view; this.manager = manager; } @Override public void playSong() { mediaManager.playMedia(); } } 

    经理类:这是核心业务逻辑代码。 也许一个主持人会有很多pipe理者(取决于视图的复杂程度)。 通常我们通过一些注入框架(如Dagger来获得Context类。

     Class MediaManagerImpl extends MediaManager { // using Dagger for injection context if you want @Inject private Context context; private MediaPlayer mediaPlayer; // dagger solution public MediaPlayerManagerImpl() { this.mediaPlayer = new MediaPlayer(context); } // no dagger solution public MediaPlayerManagerImpl(Context context) { this.context = context; this.mediaPlayer = new MediaPlayer(context); } public void playMedia() { mediaPlayer.play(); } public void stopMedia() { mediaPlayer.stop(); } } 

    最后:把这些东西放在活动,碎片……这里是你初始化视图,pipe理器和分配给演示者的地方。

     public class MyActivity extends Activity { Presenter presenter; @Override public void onCreate() { super.onCreate(); IView view = new ViewImpl(); MediaManager manager = new MediaManagerImpl(this.getApplicationContext()); // or this. if you use Dagger MediaManager manager = new MediaManagerImpl(); presenter = new PresenterImpl(view, manager); } @Override public void onStop() { super.onStop(); presenter.onStop(); } } 

    您会看到每个演示者,模型,视图都被一个界面包裹。 这些组件将通过接口调用。 此devise将使您的代码更健壮,更容易稍后修改。

    应用程序应该根据不同于通用function的function进行打包。

    我发现人们做活动,片段,适配器等等。 共同的目的包在一个组,但这是不好的做法

    大多数开发人员将它们这样分组,因为他们这样做是为了保持所有应用程序的相同包结构 。 但这是非常错误的决定,因为它们总是很难find类时,他们只是因为他们共享相同的父类分组!

    我们应该根据父类对类进行分组,但是如果我们正在制作一些API,但是如果我们正在为我们的客户定制产品,那么这是非常糟糕的做法。

    就像大多数开发人员放在活动包中的所有活动一样,因为所有的活动类都扩展了活动类。这意味着这只是与活动相关的包,但很难通过这些包。

    假设我们有一个OrderListActivity类,我们从服务器获取订单列表,然后将其显示在一个OrderListFragment类中,显然我们需要OrderListAdapter来显示订单列表。 所以当客户要求在订单列表屏幕上进行一些修改或任何function时,我们必须去许多包来满足客户的需求。 就像我们必须去活动包,并修改OrderListActivity中的一些东西,然后去OrderListFragment,然后OrderListAdapter,然后OrderListViewHolder,等等!所以这变得太难了,我们可能会在修改过程中创build问题!

    所以我们应该把正在变化/修改的class级组合在一起。

    这是最好的做法,所以我们应该把所有负责OrderListingfunction的类组合到一个包中,我们把它称为orderdlist包。

    请检查我的这个中等职位,我已经解释了包装结构:

    https://medium.com/@kailash09dabhi/mvp-with-better-naming-of-implementation-classes-dry-principle-e8b6130bbd02

    最好的做法是根据特征(有时被认为是模块)和图层来分隔东西,而不是按照他们的angular色来分类。 原因:类/接口名称已经被告知,例如LoginView,LoginPresenter,LoginFragment,LoginActivity等