【问题标题】:Android MVP: which layer should store context variableAndroid MVP:哪一层应该存储上下文变量
【发布时间】:2017-04-10 04:43:31
【问题描述】:

当用户单击视图上的按钮时,我发现自己需要播放声音文件。

MediaPlayer 需要创建上下文。

MediaPlayer初始化代码放什么最好?

我应该将上下文传递给演示者方法并在那里播放吗?

或者只在视图上播放就可以了。

【问题讨论】:

  • 一个活动就是一个上下文
  • 你应该在里面写这个活动。否则presenter没有任何意义

标签: android mvp


【解决方案1】:

Context 是 MVP 中 Android View 层的一部分,所以Presenter 一定对此一无所知,您不应该将其传递给presenter

您必须向View 接口添加一个方法,并在您的android 视图组件(即ActivityFragment)中实现它,并使用它们在View 层中执行操作作为播放声音。

Presenter 必须请求 UI 事件,View 必须处理它!

这是一个使用 DaggerRxJavaRetrofitMVP 示例,它可能会帮助您了解更多信息关于 Android 中的 MVP:

https://github.com/mmirhoseini/marvel

【讨论】:

  • 我喜欢这个答案,因为它很简短并且回答了我的问题。我基本上会将 MediaPlayer/MediaRecorder 逻辑保留在视图中。
【解决方案2】:

我经常将业务逻辑代码放在模型层中(不要与数据库中的模型混淆)。我经常重命名为XManager 以避免混淆(例如ProductManagerMediaManager ...),因此演示者类仅用于保持工作流程。

经验法则是在presenter类中没有或至少限制import android package。这个最佳实践支持您更轻松地测试演示者类,因为演示者现在只是一个普通的 java 类,所以我们不需要 android 框架来测试这些东西。

例如,这是我的 mvp 工作流程。

View 类:这是您存储所有视图(例如按钮、文本视图...)的地方,您可以在该层上为这些视图组件设置所有侦听器。同样在此视图上,您​​稍后为演示者实现定义一个侦听器类。您的视图组件将调用此侦听器类的方法。

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();
   }
}

Presenter 类: 这是您在其中存储视图和模型以供以后调用的地方。演示者类也将实现上面定义的 ViewListener 接口。主讲人的重点是控制逻辑工作流。

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();
    }
}

Manager类:这里是核心业务逻辑代码。也许一个演示者会有很多经理(取决于视图的复杂程度)。我们经常通过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();
   }
}

最后:把这些东西放在Activities、Fragments中……这里是你初始化view、manager并将所有东西分配给presenter的地方。

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();
   }
}

您会看到每个演示者、模型、视图都由一个接口包装。这些组件将通过接口调用。这种设计将使您的代码更加健壮,并且更易于以后修改。

这是一个很长的帖子来回答你的问题。我认为这很合适,因为每个人都有自己的 MVP 实现(核心流程相同,但少数派不同)。所以我在这里介绍一个我在工作中经常使用的工作流程。希望你看到这个有用:)

【讨论】:

  • 我需要在我的模型类中使用上下文来获取本地字符串(context.getString(R.string...),但是我经常听到,业务逻辑应该只包含POJO,不应该包含任何android 特定的类。但是,除了将上下文作为参数传递给模型之外,我没有找到任何解决方案。MVVM 是否解决了需要一些上下文资源的问题?
【解决方案3】:

如果你需要一个通用的上下文,你可以扩展应用程序,声明一个静态上下文变量,然后你可以把这个上下文放到你的演示者中。

【讨论】:

  • 标准警告:不要将Android上下文类放在静态字段中;这是内存泄漏(也会破坏 Instant Run)
猜你喜欢
  • 2017-09-27
  • 2019-08-07
  • 2018-12-23
  • 1970-01-01
  • 2012-07-04
  • 1970-01-01
  • 2021-11-29
  • 2018-10-28
  • 2019-03-02
相关资源
最近更新 更多