關于Android MVP模式的思考
作者:remCarpediem 發布時間:[ 2017/3/14 16:38:24 ] 推薦標簽:移動測試 Android
這一周對現有的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接口獲得數據然后自己展示。
相關推薦

最新發布
性能測試之測試環境搭建的方法
2020/7/21 15:39:32軟件測試是從什么時候開始被企業所重視的呢?
2020/7/17 9:09:11Android自動化測試框架有哪些?有什么用途?
2020/7/17 9:03:50什么樣的項目適合做自動化?自動化測試人員應具備怎樣的能力?
2020/7/17 8:57:06幾大市面主流性能測試工具測評
2020/7/17 8:52:11RPA機器人能夠快速響應企業需求,是怎么做到的?
2020/7/17 8:48:05Bug可以真正消滅嗎?為什么?
2020/7/17 8:43:03軟件測試基本概念是怎么來的?軟件測試生命周期的形成歷經了什么?
2020/7/16 9:11:10