Android开发模式:模型—视图—主导器模式

本文展示了如何在Android中采用MVP模式来优化代码结构,提高测试易用性。通过创建启动画面实例,说明了主导器如何通过接口与视图交互,实现网络状态检查与视图控制。MVP模式简化了测试用例的创建,支持TDD实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们有可能使用过MVC(Model—View—Controller)模式,但当我们用更优的方法测试Android代码时,使用MVP(模型—视图—主导器:Model—View—Presenter)模式可能更合适。MVP模式与MVC模式的根本区别是:在MVP模式中,视图中的业务逻辑被放入主导器中,主导器通过接口与视图交互。在MVC模式中,视图可以包含访问模型的逻辑。在MVP模式中,视图与模型是隔离的,所有与视图和模型的交互操作都是在主导器中完成,因此主导器在整个MVP模式中处于“主导”地位。

在接下来的demo里,我会展示如何在Android中使用MVP模式,以及如何利用该模式提高代码的易测性。为了演示其运行机制,我们创建一个启动画面。所谓启动画面,就是一个普通的界面,在应用程序开始运行前做一些初始化和验证工作。在本例中,我们会在启动画面中检查网络连接是否正常,并显示一个进度条。如果网络连接正常,就切换到另一个Activity中;否则便不会切换到其他Activity,而是向用户显示一条错误信息以阻止程序继续运行。

要创建启动画面,需要一个负责在模型和视图间交互的主导器。在本例中,主导器有两个功能:一个功能用于判断网络是否连接,另一个功能用于控制视图。

主导器中会用到一个模型类ConnectionStatus,该类实现了IConnectionStatus接口,该接口中只定义了一个判断网络是否在线的方法。源码如下所示:

public interface IConnectionStatus {
  boolean isOnline();
}

负责控制视图的代码位于Activity中,并且这个Activity实现了ISplashView接口。主导器会通过该接口控制应用程序的执行过程。ISplashView接口的源码如下所示:

public interface ISplashView {

  void showProgress();
  void hideProgress();
  void showNoInetErrorMsg();
  void moveToMainView();
}

因为我们是在Android平台上开发应用程序,因此首先需要创建视图,然后我们会把视图的控制权交给主导器。代码如下所示:

public class SplashActivity extends Activity implements ISplashView {

  private TextView mTextView;
  private ProgressBar mProgressBar;
  private SplashPresenter mPresenter;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.splash);

    //为当前Activity初始化主导器,并将当前Activity设置给主导器
    mPresenter = new SplashPresenter();
    mPresenter.setView(this);

    //Activity初始化代码
    mTextView = (TextView) findViewById(R.id.splash_text);
    mProgressBar = (ProgressBar) findViewById(R.id.splash_progress_bar);
  }

  @Override
  protected void onResume() {
    super.onResume();
    //运行onResume()方法时,通知主导器当前视图已经准备完毕,可以把控制权交给主导器了
    mPresenter.didFinishLoading();
  }

  @Override
  public void showProgress() {
    mProgressBar.setVisibility(View.VISIBLE);
  }

  @Override
  public void hideProgress() {
    mProgressBar.setVisibility(View.INVISIBLE);
  }

  @Override
  public void showNoInetErrorMsg() {
    mTextView.setText("No internet");
  }

  @Override
  public void moveToMainView() {
    startActivity(new Intent(this, MainActivity.class));
  }
}

主导器的代码比较简单,其源码如下所示:

public class SplashPresenter {

  private IConnectionStatus mConnectionStatus;
  private ISplashView mView;

  public SplashPresenter() {
    this(new ConnectionStatus());
  }

  public SplashPresenter(IConnectionStatus connectionStatus) {
    mConnectionStatus = connectionStatus;
  }

  public void setView(ISplashView view) {
    this.mView = view;
  }

  protected ISplashView getView() {
    return mView;
  }

  public void didFinishLoading() {
    //获取视图,即设置给主导器的ISplashView接口的实现类的引用
    ISplashView view = getView();

    //判断程序是否继续执行的逻辑
    if (mConnectionStatus.isOnline()) {
      view.moveToMainView();
    } else {
      view.hideProgress();
      view.showNoInetErrorMsg();
    }
  }
}

从上述代码可以看出,主导器通过接口访问视图,主导器并不知道该接口是由Activity实现的。这样,在单元测试中就更容易模拟(mock)视图。

MVP模式可以使代码更易组织且更易测试。在上述demo中,有一个测试文件夹,在测试代码中需要初始化主导器并模拟(mock)接口。在主导器中并未使用任何Android平台相关的代码,因此不需要在Android设备生运行测试用例,只需要在JVM上运行即可。此外,在本例中我们使用Mockito模拟接口。

在Android平台上开发应用程序,我们会发现Activity中会存在大量代码。遗憾的是,测试Activity是很痛苦的。使用MVP模式不仅可以简化创建测试用例的过程,还可以更容易地实施TDD(test-driven development,测试驱动开发)。

代码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值