Android開発モデル:モデル-ビュー-イニシエータモデル


MVC(Model-View-Controller)モードを使用したことがあるかもしれませんが、Androidコードをより優れた方法でテストする場合は、MVP(モデル-ビュー-リーダー:Model-View-Presenter)モードを使用するのが適切かもしれません.MVPモードとMVCモードの根本的な違いは、MVPモードでは、ビュー内のビジネスロジックがホストに格納され、ホストがインタフェースを介してビューとインタラクティブになることである.MVCモードでは、ビューはモデルにアクセスする論理を含むことができる.MVPモードでは、ビューとモデルは分離され、ビューとモデルとの相互作用はすべてマスタで行われるため、マスタはMVPモード全体で「マスタ」の地位にある.
次のdemoでは、AndroidでMVPモードを使用する方法と、このモードをどのように利用してコードの測定性を高めるかを示します.その動作メカニズムを示すために、起動画面を作成します.起動画面とは、アプリケーションが実行される前に初期化や検証を行う一般的なインタフェースです.この例では、起動画面でネットワーク接続が正常かどうかを確認し、進捗バーを表示します.ネットワーク接続が正常であれば、別のActivityに切り替えます.そうでなければ、他のActivityに切り替えるのではなく、プログラムの実行を阻止するためにユーザーにエラーメッセージを表示します.
起動画面を作成するには、モデルとビュー間のインタラクションを担当するリーダーが必要です.この例では、ホストには、ネットワークが接続されているかどうかを判断する機能と、ビューを制御する機能の2つの機能があります.
ホストでは、ネットワークがオンラインであるかどうかを判断する方法を定義するIConnectionStatusインタフェースを実装するモデルクラスConnectionStatusが使用されます.ソースコードは次のとおりです.
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、テスト駆動開発)をより容易に実施することができる.
コードアドレス