這一周對現有的Android項目進行了框架重構,使用MVP模式來重新構建整個項目和包結構。來總結一下我在這個過程中理解和實踐吧。
  MVP概述
  MVP是指Model,View和Presenter的縮寫,是MVC模式的一種改進版。MVP是一種非常適合Android應用的開發模式,它將把邏輯相關代碼從presentation Layer中分離出去 ,所以,所有界面應該顯示什么和界面如何顯示這些是相互分離的, 在理想狀態下,MVP模式可以隨意切換視圖顯示的形式。
  但是,需要首先聲明的是,MVP并不是 一個框架模式 ,它只負責presentation Layer。在Android項目中,還可能存在Domain Layer和Data Layer,它們分別負責業務邏輯和數據存儲。關于三個layer的討論,可以查看 clear Architecture 。

  The presenter
  The presenter充當的是view和model模塊中間人的角色。它從model模塊獲得數據并發送給view模塊。 但是不同于MVC,presenter模塊也決定用戶和界面交互時界面如何響應 。
  The View
  View模塊,一般由Activity或者Fragment實現,每個View實例一般都包含一個presenter實例的引用,并負責實例化presenter。理想情況下,你可以使用dagger來實現依賴注入。view的任務是當用戶操作界面時,調用presenter實例的功能來進行響應。
  The Model
  在設計良好的分層架構中,model應該只是domain layer和業務邏輯的入口,比如說, clear architecture 。但是你也可以把所有界面顯示無關的邏輯都作為model。
  MVP示例
  關于MVP架構的實例有很多,比如 google官方架構 。這里我給出一下我重構項目一個模塊的類圖,然后大致說一下實現。

  首先定義了 BaseView 和 BasePresenter 兩個接口,實現了 BaseActivity 和 BaseFragment 兩個基礎類。需要注意的是,因為每個View都需要持有一個特定類型的presenter對象,所以,在 BaseView 定義時,使用了范型。除此之外,你可以在 initPresenter 函數中構造出所需要的presenter對象。 showLoading 和 stopLoading 函數是所有視圖進行網絡數據加載時所需要的方法,其具體使用場景后邊可以看到,這里這兩個接口是在 BaseActivity 中實現的。
  public interface BaseView<T> {
  void showLoading();
  void stopLoading();
  void initPresnter();
  T getPresenter();
  }
  public interface BasePresenter {
  }
  public class BaseActivity extends Activity{
  public void showLoading() {
  }
  public void stopLoading() {
  }
  }
  public class BaseFragment extends Fragment {
  public void showLoading() {
  }
  public void stopLoading() {
  }
  }
  然后是data模塊中的相關類和接口的定義。我們在 DataContract 接口中定義所有相關的view和data。
  public interface DataContract {
  interface DataView extends BaseView<DataPresenter> {
  void showFragment(BaseFragment fragment);
  }
  interface DataPresenter extends BasePresenter {
  void switchToDataList();
  void switchToDataTree();
  }
  interface DataListView extends BaseView<DataListPresenter> {
  void showDataList(List<String> data);
  }
  interface DataListPresenter extends BasePresenter {
  void loadDataList();
  }
  interface DataTreeView extends BaseView<DataTreePresenter> {}
  interface DataTreePresenter extends BasePresenter {}
  }
  在 DataContract 接口中,我們可以清晰的看到這個模塊中所有的view和presenter類型和他們的接口。這樣無疑可以幫助其他程序員快速了解本模塊的業務邏輯。下面,我們來看一下 DataListFragmnet 和 DataListPresenter 的實現。
  public class DataListFragment extends BaseFragment implements DataContract.DataListView {
  private DataContract.DataListPresenter mPresenter;
  @Override
  public void initPresnter() {
  mPresenter = new DataListPresenter(this);
  }
  @Override
  public DataContract.DataListPresenter getPresenter() {
  return mPresenter;
  }
  @Override
  public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  initPresnter();
  //需要加載數據或者接收到界面點擊事件時,調用presenter接口進行初始化或者響應。
  mPresenter.loadDataList();
  }
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
  Bundle savedInstanceState) {
  return inflater.inflate(R.layout.fragment_data_list, container, false);
  }
  @Override
  public void showDataList(List<String> data) {
  //將數據傳給adapter等數據展示的視圖
  }
  }
  public class DataListPresenter implements DataContract.DataListPresenter {
  private DataContract.DataListView mView;
  public DataListPresenter(DataContract.DataListView view) {
  super();
  this.mView = view;
  }
  @Override
  public void loadDataList() {
  //調用baseview的接口,這些接口實現在baseFragment或者BaseActivity中
  mView.showLoading();
  //getdata from network
  mView.stopLoading();
  mView.showDataList(Arrays.asList("a","b","c"));
  }
  }
  上述代碼中有很多可以好好思考的地方。首先是 showLoading 和 stopLoading 這兩個函數。這兩個函數接口定義在 BaseView ,實現在 BaseFragment ,所以當 DataListFragment 繼承了 BaseFragment 并且實現了 BaseView 時,它并不需要再次定義上述兩個接口,畢竟在一個app中,網絡加載時的laoding動畫一般都是一致的。然后是view和presenter之間函數調用的問題。首先,view在需要初始化或者需要處理點擊事件時,需要調用presenter的函數,而不是自己來進行處理。而且二者之間的數據傳遞必須是presenter調用view的接口傳遞給view數據,而不是view調用presenter接口獲得數據然后自己展示。