前言
在現實項目中,我們經常會遇到這樣一種情況,就是一個Activity類不僅要處理幾種業務邏輯,同時還要兼顧着數據的請求以及UI的操作,這樣造成的後果就是整個類的代碼會出現上千行,更有勝者是幾千行。顯而易見,這種處理方式是不妥的,不僅違反了面向對象中單一職責原則,而且對於整個項目來說,也不利於項目的擴展和維護。(單一職責原則:不要存在多於一個導致類變更的原因。通俗的說,即一個類只負責一項職責。)那麼,面對這種情況,我們該如何去架構整個項目?由於android項目本身就是MVC架構的體現,Activity充當了Controller,所以我們需要一種新的架構去替代MVC。
MVP初步瞭解
MVP:(Model-View-Presenter)它是從MVC模式演變而來的,它與MVC模式相同的地方是,Controller/Presenter負責邏輯的處理,Model提供數據,View負責展示。作爲一種新的模式,MVP與MVC有着一個重大的區別,在MVP中View並不直接使用Model,它們之間的通信是通過Presenter來進行的,所有的交互都發生在Presenter內部,而在MVC中View會從Model中讀取數據而不是通過Controller。
MVC圖示
MVP圖示
使用MVP的優點:
- 模型與視圖完全分離,我們可以修改視圖而不影響模型
- 可以更高效的使用模型,因爲所有的交互都發生在一個地方,即Presendter內部
- 我們可以將一個Presenter用於多個視圖,而不需要改變Presenter的邏輯。這個特性非常有用,因爲視圖的變化總是比模型的變化頻繁。
- 如果我們把邏輯放在Presenter中,那麼我們就可以脫離用戶來測試這些邏輯(單元測試)
MVP在Android中使用
- View層負責處理用戶時間和視圖部分的展示,在Android中,它可能是Activity或者Fragment類
- Model層負責訪問數據。數據可以是遠程Server API,本地數據庫或者Share的Preference等
- Presenter層是鏈接(或適配)View和Model的橋樑
示例
項目結構
定義一接口INewsView,作爲View層和Presenter層關聯的紐帶,View層去實現該接口,而Presenter通過INewsView進行改變Activity的UI,同時Presenter類也和Model層進行關聯操作
INewsView接口
public interface INewsView {
void initView();//初始化控件
void startLoad();//開始請求數據
void loadSuccess(List<NewsBean> newsBeanList);//請求成功,數據不爲空
void loadFail();//請求失敗
void loadEmpty();//請求成功,數據爲空
}
Activity類去實現該接口,進行UI邏輯操作
public class MainActivity extends AppCompatActivity implements INewsView{
private NewsPersenter newsPersenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
newsPersenter = new NewsPersenter(this);
newsPersenter.requestData();
}
@Override
public void initView() {
//初始化控件
}
@Override
public void startLoad() {
//請求數據前UI操作
}
@Override
public void loadSuccess(List<NewsBean> newsBeanList) {
//請求成功,數據不爲空,UI操作
}
@Override
public void loadFail() {
//請求失敗,UI操作
}
@Override
public void loadEmpty() {
//請求成功,數據爲空,UI操作
}
}
NewsPresenter類
public class NewsPersenter {
private INewsView iNewsView;
public NewsPersenter(INewsView iNewsView) {
this.iNewsView = iNewsView;
this.iNewsView.initView();
}
public void requestData() {
//請求數據前數據前UI操作
iNewsView.startLoad();
//請求數據,異步請求
NewsHttpRequest.requestNewsList(new Callback<List<NewsBean>>() {
@Override
public void onResponse(Response<List<NewsBean>> response) {
if (response == null || response.body() == null || response.body().isEmpty()) {
//請求成功,無數據
iNewsView.loadEmpty();
} else {
//請求成功,有數據
iNewsView.loadSuccess(response.body());
}
}
@Override
public void onFailure(Throwable t) {
//請求失敗
iNewsView.loadFail();
}
});
}
}
NewsHttpRequest類,進行數據請求,Model層操作
public class NewsHttpRequest {
public static interface INewsRequest {
@GET("/NewsService/newsList")
Call<List<NewsBean>> getNewsBeanList();
}
public static void requestNewsList(Callback<List<NewsBean>> callBack) {
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://localhost:8080")
.addConverterFactory(GsonConverterFactory.create())
.build();
retrofit.create(INewsRequest.class).getNewsBeanList().enqueue(callBack);
}
}
ps:當項目比較小,業務邏輯不多的時候,不建議使用MVP模式