編輯:關於Android編程
最近經常看到各種介紹MVP模式的博客的,之前寫過不少的Android應用,在做那些應用的時候,都是要求快速完成,所以從開始設計到寫代碼就一直考慮著重用。以前寫的項目基本都是不斷重構項目,將項目代碼變得更加精簡,提高代碼之間的復用性。但是代碼並沒有特別地注重按照MVC模式或者是MVP模式來,更多的是直接考慮模塊化,重用,精簡。所以看了MVP模式後,決定去總結一下自己代碼中的問題並優化,算是對自己之前寫的代碼的回顧。
MVP框架是目前在Android流行起來的框架,它非常適合用於Android開發上面。我最早接觸MVP模式是在一本敏捷開發的書上。MVP分別指代M(model),V(View),P(Presenter):
- M(Model):表示數據模型,以及相關的數據結構。
- V(View):表示視圖,主要是指UI界面相關的那些東西。在Android裡面比如說layout的xml文件,在MVP中,很多時候Activity/Fragment也是被看做View。
- P(Presenter):可以直接理解為視圖與模型的中間紐帶。
vcq9ysfU9rzT0ru49klNb2RlbL3Tv9q6zUlWaWV3vdO/2qOs08NNb2RlbLrNVmlld7fWsfDKtc/WxMfBvbj2vdO/2qOsUHJlc2VudGVywO/D5rGjtOZJTW9kZWy6zUlWaWV3vdO/2sDg0M21xLPJ1LGx5MG/oaM8L3A+DQo8aDIgaWQ9"代碼示例">代碼示例
下面舉一個關於Android用戶信息的MVP模式例子。
public interface IUserView{
void setName(String name);
}
用戶的JavaBean—User:
class User{
private String name;
private String id;
public String getName(){
return name;
}
public String getId(){
return id;
}
public void setName(String name){
this.name = name;
}
public void setId(String id){
this.id = id;
}
}
用戶模型接口
public interface IUserModel{
void saveUser(User user);
User load();
}
真正模型
public class UserModel implements IUserModel{
void saveUser(User user){
// 保存用戶信息,保存在本地數據庫中,或者xml裡面
}
User loadUser(){
// 從網絡中,或者從本地緩存中讀取用戶信息
return null; //未實現
}
}
Presenter:
public class UserPresenter{
private IUserView view;
private IUserModel userModel;
public UserPresenter(IUserView view){
this.view = view;
userModel = new UserModel();
}
public void loadUser(){
// 此處可能是異步load
User user = userModel.loadUser();
view.setName(user.getName());
}
}
把Activity作為View來看待
public class UserActivity extends Activity implements IUserView{
TextView tvName; //名稱對應的TextView
UserPresenter userPresenter ;
public void onCreate(Bundle bundle){
...
userPresenter = new UserPresenter(this);
// userPresenter.loadUser(); 可以有先初始化
}
void setName(String name){
tvName.setText(name); //如果presenter的loadUser是異步線程,這裡可以通過tvName.post來運行在UI線程。
}
void reloadUserData(){ //該函數可以某個按鈕的onClick事件裡面調用
userPresenter.loadUser(); // 可以是從網絡中加載數據
}
}
上面代碼中Activity不再與Model直接關聯,而是通過Presenter來間接關聯Model。並且當Model的數據變化了的時候,Presenter能夠通知View。上面的例子是View需要變化了,請求Presenter獲取數據。
MVP與MVC最大的不同就是View和Model不再直接關聯。很多Android的MVC模式都是直接將Activity看作Control,這會導致整個Activity非常臃腫,因為它既然進行UI交互,還需要加上Control這部分的功能。另外即使另外新建一個Control,而把Activity只當做View的功能,如果Activity還是直接跟Model直接關聯的話,因為跟Model直接關聯,還是會在Activity增加很多操作。而使用P作為Model和View的紐帶,P可以先對模型數據進行一些處理,然後再顯示到View。另外一方面對於View的一些請求,Presenter也可以進行一些處理再去請求Model。
上面是關於代碼方面的優勢,其實通過分隔開Model和View,也是將各個模塊進行了解耦。另外一方面通過增加IUserView和IUserModel,這樣每個部分進行單元測試也更加方便了,比如可以直接實現IUserView來模擬測試Presenter。
個人覺得MVP模式適合Android應用,一個很大的原因就是Activity這種組件的存在,UI交互完全放在了Activity裡面,這導致很多時候Activity會在一不注意間就變得臃腫。View過於龐大。當然還有很多跟Android相關的優勢,比如說能夠更好地避免Activity的內存洩漏(Presenter直接引用View,而不是Activity的時候)。其實通過增加Presenter,一定程度上也增加了Presenter的復用,很多人說View和Presenter是一一對應的,但是我覺得如果不一一對應,比如說一個Activity裡面包含多個Presenter,將Presenter細化,那樣Presenter復用的可能性也就越高了,同時也避免了Presenter過於臃腫。
平時自己寫代碼的時候,其實還真的是比較少那麼明顯地使用這種MVP模式,或者說是MVC模式。更多的是模塊化,類層次化(面向對象),面向切面,並且堅持代碼精簡,復用的原則。下面介紹一個將平時的項目簡化後的模式,並且通過考慮優化結構將模式轉變成MVP的過程。先看看下面這種類型結構:
先模塊化將程序分為Fragment/Activity部分,Adapter部分,模型網絡操作部分,通過將相關類進行層次化來減少類的臃腫,另外通過AOP編程的方式將一些內容從子父類中提取出來,作為一個單獨的切面。這種面向切面能夠提高代碼的復用性。
上面的類型圖裡面也有一個不合理的例子,正如上面的注釋中所說的將網絡操作作為模型的一部分,而不是再添加一個接口,會導致網絡操作一旦修改,會影響到Model的子類。
下面看看如何對上面的結構進行轉換。上面這種結構更多的是MVC的方式,而且是將V和C基本合在一起了,內聚在一起能夠更方面UI交互,但是也會導致臃腫。上面的圖中發現只有BaseFragment單向地去關聯Model,這樣勢必會導致Fragment增加更多的代碼來控制,因為在Android中進行網絡連接是一定要在非UI線程操作的,如果Model沒有關連Fragment,必然需要將一個異步操作放到Fragment,等待Model操作完成了後,Fragment來更新Fragment的內容。如果增加一個接口,然後Fragment實現,並且用Model引用它,那麼將能夠減少Fragment的操作,而且能夠更好地去對Model進行單元測試。如果增加一個Presenter,由Presenter與Fragment相互關聯,然後Presenter也與Model相互關聯,那麼Fragment將會大大簡化,更加專注一些其他的UI交互。增加Presenter整個架構就變成了MVP模式了。重構後的類型圖如下:
模式總是堅持著復用,模塊間低耦合,模塊內高內聚等等原則來進行的,設計模式中就有六大原則: 單一職責原則,開閉原則,依賴倒轉原則,迪米特法則,裡氏替換原則,組合聚合原則。好的模式能夠讓人在閱讀的時候能夠很好地理解代碼,在對程序進行修改的時候能夠快速簡潔,並且不對原有代碼結構破壞。
本文Github代碼鏈接https://github.com/AndroidMsky/AndoirdIOSPicker 先上圖吧:這是筆者最近一個項目一直再用的一個選擇器
Android圖片的拖拽與縮放2014年5月9日 我們在使用應用當中經常需要浏覽圖片,比如在微信當中,點擊圖片之後可以對圖片進行縮放。 本博客介紹如何對圖片進行拖拽和縮
今天是放完假後工作的第一天,為了證明我不是一段幽靈代碼,我給各位看客老爺們說句:祝大家節日過得愉快(過得不愉快那也是人之常情)。我們繼續來講一講ListView的開發,
一 概述我們用ItemDecoration為RecyclerView打造了帶懸停頭部的分組列表。其實Android版微信的通訊錄界面,它的分組title也不是懸停的,我們