前言
寫Android:你是如何把Activity寫的如此“萬能”的這篇文章到現(xiàn)在已經(jīng)好久了,但是由于最近事情較多锚沸,寫重構(gòu)篇的計劃就一直被無情的耽擱下來了第晰,借這幾天還算有點(diǎn)空余時間碱茁,把自己這樁心事了解下裸卫。
其實(shí)大家也知道Android:你是如何把Activity寫的如此“萬能”的這篇文章只是個引子,其實(shí)我真正想引出的是mvp設(shè)計模式纽竣,因?yàn)樽罱约鹤罱谟胢vp做項(xiàng)目墓贿,自己對mvp有一些感悟,因此我將用mvp進(jìn)行“萬能”activity的重構(gòu)退个。
同時也有一些朋友與我交流mvp募壕,他們會被mvp中的m,v,p都應(yīng)該放什么邏輯而困惑?會被mvp中的m應(yīng)該怎么寫而困惑语盈?會被一個界面舱馅,怎么按照mvp來進(jìn)行重構(gòu)感到困惑?會被listview的adapter應(yīng)該放在m層還是p層困惑刀荒?
我希望通過本文的講解能幫助大家對mvp有一個更深的了解代嗤,現(xiàn)在進(jìn)入主題內(nèi)容。
正文內(nèi)容
本文內(nèi)容分為2部分:
- 帶你了解mvp
- 使用mvp對“萬能”Activity進(jìn)行重構(gòu)
第一部分會深入了解mvp到底是什么缠借,它的好處等知識干毅。第二部分會講解如何利用mvp來重構(gòu)“萬能”Activity。
帶你了解mvp
任何軟件都是以數(shù)據(jù)為中心泼返,為了能與用戶進(jìn)行交互硝逢,就需要提供界面支持用戶對數(shù)據(jù)進(jìn)行增刪改查操作。
不管是mvc绅喉,mvp還是mvvm始終都在做一件事情:怎么樣能更好的解決數(shù)據(jù)與界面之間的關(guān)系渠鸽,以達(dá)到數(shù)據(jù)與界面之間的耦合更低,代碼的復(fù)用性更高柴罐,代碼的可測性更好徽缚。
本文的重點(diǎn)是講解mvp,因此讓我們開始了解下mvp是怎么組織數(shù)據(jù)與界面之間的關(guān)系的革屠。我們先從mvp的結(jié)構(gòu)圖說起凿试。
mvp的面容
網(wǎng)上有些關(guān)于mvp的結(jié)構(gòu)圖基本是以下樣子
我覺得這張圖是有問題的,問題在于presenter把請求轉(zhuǎn)交給model似芝,model應(yīng)該把處理結(jié)果返回給presenter那婉,這張圖是沒有反映這個過程的。
正確的mvp的結(jié)構(gòu)圖是這樣子的
我們先看下能從這張圖中得到哪些信息国觉?
- mvp的分層結(jié)構(gòu)特別類似于網(wǎng)絡(luò)的七層協(xié)議吧恃,每層只知道自己依賴層的細(xì)節(jié)。
- 這種分層的好處是:層與層之間的耦合性低麻诀,模塊的復(fù)用性高痕寓,可維護(hù)性更好,每層可以單獨(dú)存在蝇闭,這樣可測性更好呻率。
- 數(shù)據(jù)流的走向可以是:view-->presenter-->model-->presenter-->view,這種數(shù)據(jù)流一般出現(xiàn)的場景是用戶在界面觸發(fā)了一個事件的情形下
- 數(shù)據(jù)流的走向也可以是:model-->presenter-->view,這種數(shù)據(jù)流一般出現(xiàn)于比如通過長鏈接接收消息的場景呻引。
- 不管數(shù)據(jù)流是怎樣的一個流動走向礼仗,始終有一個原則是:數(shù)據(jù)流不能跨層流動,即層與層不能跨層通信逻悠。
看了mvp的整體結(jié)構(gòu)圖元践,我們以從底層到上層的順序依次來介紹model,presenter童谒,view单旁。
model
先說下一些關(guān)于model的錯誤理解:
- model是實(shí)體類的集合
- 比如從json中解析數(shù)據(jù)的代碼應(yīng)該放在presenter中
- model與mvc中的model是一樣的
關(guān)于model的正確理解我們會在文中看到。
數(shù)據(jù)加工處理廠
通過應(yīng)用mvp后的感受饥伊,我個人的感覺model是最難寫的一層象浑,并且也是最難懂的,因?yàn)閙odel是整個應(yīng)用或界面的數(shù)據(jù)加工處理廠琅豆,所謂數(shù)據(jù)加工廠就是對數(shù)據(jù)的獲取愉豺,數(shù)據(jù)的解析,數(shù)據(jù)的存儲茫因,數(shù)據(jù)的分發(fā)蚪拦,數(shù)據(jù)的增刪改查等操作。意思就是凡是涉及到數(shù)據(jù)操作都是在model進(jìn)行的冻押,所以model不僅僅只是實(shí)體類的集合驰贷,同時還包含關(guān)于數(shù)據(jù)的各種處理操作。
三種數(shù)據(jù)源
數(shù)據(jù)的數(shù)據(jù)源有三種:內(nèi)存翼雀,磁盤(文件或數(shù)據(jù)庫等)饱苟,網(wǎng)絡(luò)。為了提升app的性能狼渊,有必要把經(jīng)常訪問的數(shù)據(jù)臨時存入內(nèi)存中箱熬;同時也為了提升app性能和為用戶省流量省電,有必要把數(shù)據(jù)存入磁盤中狈邑;還有的數(shù)據(jù)是有必要從網(wǎng)絡(luò)讀取的城须。三個數(shù)據(jù)源不一定同時存在,比如不與網(wǎng)絡(luò)交互的app米苹,不存在網(wǎng)絡(luò)數(shù)據(jù)源糕伐。所以凡是涉及到關(guān)于數(shù)據(jù)發(fā)生于三個數(shù)據(jù)源加工處理的操作的代碼都要放在model中。
model為上層提供的服務(wù)
model從黑盒的角度來看為上層(指依賴于model的層比如present)提供的服務(wù)無非就2種:model為上層提供數(shù)據(jù)蘸嘶,model處理上層傳遞的數(shù)據(jù)
model為上層提供數(shù)據(jù)
上層會從model中去數(shù)據(jù)良瞧,那model會從三數(shù)據(jù)源中取數(shù)據(jù)陪汽,取的順序是
- 先內(nèi)存,內(nèi)存取到數(shù)據(jù)返回
- 其次磁盤褥蚯,磁盤取到數(shù)據(jù)挚冤,如有必要把數(shù)據(jù)存儲在內(nèi)存中,則需要進(jìn)行
存儲赞庶,返回數(shù)據(jù) - 最后網(wǎng)絡(luò)训挡,網(wǎng)絡(luò)取到數(shù)據(jù),如有必要在磁盤或內(nèi)存中存儲歧强,則進(jìn)行存儲澜薄,返回數(shù)據(jù)
上面的取數(shù)據(jù)過程是最簡單的情況,復(fù)雜些還會涉及到從內(nèi)存或磁盤中取到的數(shù)據(jù)是否過期摊册,過期的話就應(yīng)該從網(wǎng)絡(luò)獲取肤京。從網(wǎng)絡(luò)取得數(shù)據(jù)后需要把內(nèi)存或磁盤的數(shù)據(jù)更新。
model處理上層傳遞的數(shù)據(jù)
model接收到上層傳遞的數(shù)據(jù)后丧靡,model會依次把數(shù)據(jù)扔給三個數(shù)據(jù)源去處理蟆沫,有可能三個數(shù)據(jù)源都會處理數(shù)據(jù),有可能只是其中一個處理温治,model會把處理的結(jié)果返回饭庞。
所以model會把解析好的數(shù)據(jù)提供給上層,上層對于數(shù)據(jù)的來源完全是透明的熬荆,上層完全不需要關(guān)心數(shù)據(jù)到底是來自內(nèi)存舟山,還是磁盤甚至是網(wǎng)絡(luò)。同理上層只需要的把數(shù)據(jù)扔給model卤恳,上層唯一做的事情就是愉快的等待處理結(jié)果累盗。
tip
mvc中的model是要和view進(jìn)行交互的,而mvp中的model不會知道任何view的細(xì)節(jié)突琳。
model中的所有操作都發(fā)生于普通線程若债。
關(guān)于model的介紹先到此,我們在來看下presenter拆融。
presenter
presenter翻譯成漢語的意思是主持人蠢琳,提出者。從它的意思可以看出它有控制全場的作用镜豹。首先presenter是處于mvp的中間層傲须,在view和model中起一個承上啟下的作用。presenter會把view交給自己的命令進(jìn)行一定的校驗(yàn)等操作交給model處理趟脂,會把model處理的結(jié)果交給view泰讽。
presenter封裝業(yè)務(wù)
presenter不僅起一個橋梁的作用,它還會把業(yè)務(wù)邏輯代碼給包攬下來。這樣就可以減輕Activity的負(fù)擔(dān)了已卸,讓Activity全心全意做它的view工作佛玄。那估計就有朋友犯迷糊了,哪些代碼屬于業(yè)務(wù)邏輯呢咬最?比如一些校驗(yàn)代碼翎嫡∏范或者可以這樣想只要是不屬于view和model的代碼基本都可以放在presenter中永乌。
presenter負(fù)責(zé)刷新view
mvc或以前的關(guān)于view的寫法一般都是這樣,view在接收到數(shù)據(jù)后具伍,自己來進(jìn)行view的刷新或其他操作翅雏。但是mvp中presenter負(fù)責(zé)對view進(jìn)行刷新,比如從model獲取的數(shù)據(jù)人芽,presenter會根據(jù)獲取的數(shù)據(jù)成功與否來通知view應(yīng)該是顯示成功界面還是失敗界面望几。這樣就讓Activity變的更輕了,變成了聽別人指揮的傻白甜了萤厅。這時候的presenter就有點(diǎn)主持人橄抹,掌控者的味道了。
presenter持有的線程
Android中view的操作需要在ui線程里執(zhí)行惕味,其他耗時操作需要在普通線程執(zhí)行楼誓。presenter會持有這2種線程:ui線程,普通線程。刷新view時名挥,它切換為ui線程進(jìn)行刷新疟羹,從model取數(shù)據(jù)切換為普通線程。假如使用rxjava的話禀倔,就特別簡單了關(guān)于線程切換的事情榄融。
tip
presenter從model中獲取的數(shù)據(jù)就是解析好的數(shù)據(jù),不需要出現(xiàn)解析數(shù)據(jù)的代碼救湖。
接著我們來看下view愧杯。
view
view層就很好理解了,就是用戶直接看到的界面鞋既,mvp中的view是很省心的力九,比如更新view,接收數(shù)據(jù)涛救。這些操作它都不需要操心畏邢,也不需要知道數(shù)據(jù)到底來自哪里,給我啥我顯示啥就可以了检吆。
一個view可以同時擁有多個presenter舒萎,也可以只有一個presenter。
Android中的Activity,F(xiàn)ragment在mvp中是作為view來使用的臂寝,這些Activity章鲤,F(xiàn)ragment的責(zé)任就小了,只關(guān)心界面相關(guān)的事情足矣咆贬。
各種Adapter是放在view層的败徊。
總結(jié)
我們初步認(rèn)識了mvp,mvp中的model掏缎,present皱蹦,view到底是什么,他們之間的關(guān)系是什么樣的眷蜈,這只是初步認(rèn)識mvp沪哺,關(guān)于mvp中還有很多細(xì)節(jié)需要介紹,比如android clean architecture 中model和presenter之間多了一層interactor,多的這層interactor是用來做什么的酌儒,model層是怎么架構(gòu)的辜妓。google mvpmodel層要比android clean architecture 簡單等,希望能在我后面的章節(jié)看到相關(guān)關(guān)于每層的詳細(xì)介紹忌怎。我們開始進(jìn)入我們的重構(gòu)"萬能"Activity的部分籍滴。
使用mvp設(shè)計模式對"萬能"Activity進(jìn)行重構(gòu)
回憶下“萬能”Activity的樣子
我在上篇文章的“萬能”的LoginActivity基礎(chǔ)上增加了登錄對話框的功能,“萬能”LoginActivity的代碼如下:
public LoginActivity extends Activity{
private EditText mUserNameView, mPasswordView;
private Button mLoginView;
public void initViews(){
.......
各種findViewById.....代碼
//給登陸按鈕加監(jiān)聽器
mLoginView.OnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String userName = mUserNameView.getText();
String password = mPasswordView.getText();
//驗(yàn)證用戶輸入的密碼是否合法
if(!validate(userName) || !validate(password)){
告訴用戶輸入的用戶名或密碼不合法
} else{
//開始登陸
login(userName,password);
}
}
});
}
//登陸方法,用偽代碼來寫下網(wǎng)絡(luò)請求
private void login(String userName,String password){
//增加登錄進(jìn)度對話框給用戶友好用戶體驗(yàn)
顯示登錄進(jìn)度對話框...
HttpClient.getInstance().login(userName,password,
new ResponseListener(){
public void failed(Failed failed){
把登錄進(jìn)度對話框消失...
做失敗相關(guān)的處理工作榴啸,比如給用戶提示
把密碼輸入框清空孽惰,還比如登陸次數(shù)限制等
}
public void success(Response response){
把登錄進(jìn)度對話框消失...
做成功相關(guān)的處理工作
//暫且把用戶信息的類叫做UserInfo,從json中解析數(shù)據(jù),假設(shè)response.getContent()存在
String jsonContent = response.getContent();
JsonObject jsonObject = new JsonObject(jsonContent);
UserInfo userInfo = new UserInfo();
userInfo.name = jsonObject.optString("name");
userInfo.userId = jsonObject.optString("userId");
其他字段的解析......
//保存userInfo信息到數(shù)據(jù)表中,假設(shè)userDatabase已經(jīng)存在
userDatabase.save(userInfo);
跳到app的主頁
}
});
}
//驗(yàn)證給定的字符串是否合法插掂,true 合法灰瞻,false 不合法
private boolean validate(String str){
}
}
我們回憶了“萬能”LoginActivity的代碼后,開始重構(gòu)辅甥。
開始重構(gòu)
model
在使用mvp時酝润,我一般有個習(xí)慣就是首先從model->presenter->view的順序?qū)懘a,所以重構(gòu)“萬能”LoginActivity也先從model開始璃弄。前半部分關(guān)于model介紹過要销,model從黑盒的角度來說只有2個功能:一個是輸出數(shù)據(jù),一個是輸入數(shù)據(jù)夏块。因此登錄中presenter只需要把賬號疏咐,密碼交給model,presenter唯一做的事情就是監(jiān)聽登錄狀態(tài)即可脐供。model會把presenter傳遞的賬號浑塞,密碼交給服務(wù)器,model在把服務(wù)器返回的數(shù)據(jù)進(jìn)行解析政己,存儲在磁盤或內(nèi)存中酌壕,把解析好的數(shù)據(jù)傳遞給presenter。那我們看下偽代碼:
//管理登錄的類,它是單例的,這就不寫單例方法了
public class LoginManager{
//登錄的監(jiān)聽器
public static interface LoginListener{
//登錄成功
void onSuccessLogin(UserEntity user);
//登錄失敗
void onFailedLogin(Failed failed);
}
//登錄方法
public void login(String name,String password,final LoginListener loginListener){
//假設(shè)HttpClient是一個請求網(wǎng)絡(luò)服務(wù)的類
HttpClient.getInstance().login(userName,password,
new ResponseListener(){
public void failed(Failed failed){
loginListener.onFailedLogin(failed);
}
public void success(Response response){
//假設(shè)UserParse類已經(jīng)存在卵牍,主要用來從response中解析UserEntity
UserEntity userEntity = UserParse(response.getContent());
//假設(shè)userDatabase是數(shù)據(jù)庫存儲類
userDatabase.store(userEntity);
//還可以把userEntity存入內(nèi)存中果港,這得根據(jù)業(yè)務(wù)需求進(jìn)行處理
loginListener.onSuccessLogin(userEntity);
}
});
}
}
登錄的model層我們沒有做的那么復(fù)雜,比如把服務(wù)器返回的用戶信息存儲在內(nèi)存中糊昙,把服務(wù)器返回的token存儲在磁盤中辛掠,實(shí)現(xiàn)自動登錄功能等,本例子只是一個特別簡單的登錄功能释牺,實(shí)際應(yīng)用中登錄需要考慮很多的東西萝衩,登錄的modle層到此重構(gòu)完畢。
presenter
上文中提到過presenter船侧,presenter起連接view與model的作用欠气,presenter封裝業(yè)務(wù)作用,presenter有負(fù)責(zé)刷新view的作用镜撩。
我們梳理下presenter都應(yīng)該包含哪些功能:
- 驗(yàn)證賬號,密碼的合法性.
- 把驗(yàn)證成功的賬號队塘,密碼交給model層
- 把登錄的狀態(tài)傳遞給view層袁梗,并根據(jù)不同的登錄狀態(tài)通知view顯示不同的界面
那讓我們開始寫代碼,presenter層的類組織結(jié)構(gòu)我是參照google mvp的presenter類組織結(jié)構(gòu)來進(jìn)行的憔古,因?yàn)槲艺J(rèn)為google mvp presenter類結(jié)構(gòu)更清晰遮怜,看下偽代碼:
//登錄的條約接口,分別定義了登錄view的一些方法鸿市,和登錄presenter的一些方法
public interface LoginContract{
//需要view層來實(shí)現(xiàn)的登錄view接口锯梁,IView是所有view的基類
interface ILoginView extends IView{
void onShowSuccessLoginView(UserInfo userInfo);
void onShowFailedLoginView(int failed);
void showLoginingView();
void dissLoginingView();
}
//定義了登錄presenter的一些方法,IPresenter是所有Presenter的基類
interface ILoginPresenter extends IPresenter<ILoginView>{
void login(String name,String password);
}
}
public interface IView{
void initView();
}
//IPresenter提供了一些基礎(chǔ)方法焰情,其實(shí)這些方法是對應(yīng)Activity或Fragment的生命周期方法
public interface IPresenter<V extends IVew>{
void onStop();
void onResume();
void onDestroy();
void onPause();
void onStart();
void init(V view);
}
//登錄的presenter
public class LoginPresenter implements ILoginPresenter{
private ILoginView mLoginView;
private LoginManager mLoginManager = LoginManager.getInstance();
public void init(ILoginView loginView){
mLoginView = loginView;
mLoginView.initView();
}
public void login(String name,String password){
//驗(yàn)證name陌凳,password的合法性,
if(validate(name) && validate(password)){
//假設(shè)NormalThread.exe方法可以讓操作在普通線程里執(zhí)行
mLoginView.showLoginingView();
NormalThread.exe(new Runnable(){
public void run(){
mLoginManager.login(name,password,
new LoginListener(){
public void onSuccessLogin(UserEntity userEntity){
//UserMapper類,負(fù)責(zé)把底層的UserEntity轉(zhuǎn)化為view層使用的UserInfo
UserInfo userInfo = UserMapper.map(userEntity);
//下面的代碼在ui線程中執(zhí)行内舟,這就不寫具體的實(shí)現(xiàn)了
mLoginView.onShowSuccessLoginView(userInfo);
mLoginView.dissLoginingView();
}
public void onFailedLogin(Failed failed){
//下面的代碼在ui線程中執(zhí)行合敦,這就不寫具體的實(shí)現(xiàn)了
mLoginView.onShowFailedLoginView(failed.failedState);
mLoginView.dissLoginingView();
}
});
}
}
}else{
//假設(shè)1代表賬號,密碼不合法
mLoginView.onShowFailedLoginView(1);
}
}
}
以上登錄的Presenter層的偽代碼都是關(guān)鍵代碼验游,讓我們看下以上代碼都做了什么充岛?
- LoginContract 把ILoginView和ILoginPresenter組合在一塊,ILoginView定義了提供給ILoginPresenter的方法耕蝉,ILoginPresenter定義了提供給ILoginView的方法崔梗。只需要看LoginContract就可以知道登錄的view層和presenter層之間的約定。我很喜歡XXContract類垒在,也推薦大家使用
- IView是一個基礎(chǔ)接口蒜魄,提供一些公用方法
- IPresenter是一個基礎(chǔ)接口,它把Activity或Fragment的生命周期方法集合了起來。有了這些生命周期方法权悟,presenter就讓Activity一心一意做它的view相關(guān)的工作砸王。
到此登錄Present的重構(gòu)結(jié)束,我們重構(gòu)view層峦阁。
view
view層就很簡單了谦铃,只是需要把基礎(chǔ)設(shè)施建立好,直接看偽代碼:
public abstract class BaseActivity extends FragmentActivity{
private Set<IPresenter> mAllPresenters = new HashSet<IPresenter>(1);
/** * 獲取layout的id榔昔,具體由子類實(shí)現(xiàn)
* @return
*/
protected abstract int getLayoutResId();
/**
*需要子類來實(shí)現(xiàn)驹闰,獲取子類的IPresenter,一個activity有可能有多個IPresenter
*/
protected abstract IPresenter[] getPresenters();
//初始化presenters撒会,
protected abstract void onInitPresenters();
/** * 從intent中解析數(shù)據(jù)嘹朗,具體子類來實(shí)現(xiàn)
* @param argIntent
*/
protected void parseArgumentsFromIntent(Intent argIntent){
}
private void addPresenters(){
IPresenter[] presenters = getPresenters();
if(presenters != null){
for(int i = 0; i < presenters.length; i++){
mAllPresenters.add(presneters[i]);
}
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResId());
if(getIntent() != null){
parseArgumentsFromIntent(getIntent());
}
addPresenters();
onInitPresents();
}
@Override
protected void onResume() {
super.onResume();
//依次調(diào)用IPresenter的onResume方法
for (IPresenter presenter:mAllPresenters ) {
if(presenter != null){
presenter.onResume();
}
}
}
...其他生命周期方法也是類似,調(diào)用IPresenter中相應(yīng)的生命周期方法...
}
基礎(chǔ)設(shè)施已經(jīng)ok了诵肛,這時候我們就該重構(gòu)"萬能“LoginActivity了屹培。
public class LoginActivity extends BaseActivity implements LoginConstract.ILoginView{
private LoginPresenter mLoginPresenter = new LoginPresenter();
protected int getLayoutResId(){
return R.layout.activity_login;
}
protected IPresenter[] getPresenters(){
return new IPresneter[]{ mLoginPresenter};
}
//初始化presenters,
protected void onInitPresenters(){
mLoginPresenter.init(this);
}
public void initView(){
...初始化view的代碼...
//
mLoginButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mLoginPresenter.login(name,password);
}
});
}
public void onShowSuccessLoginView(UserInfo userInfo){
....顯示登錄成功界面....
}
public void onShowFailedLoginView(int failed){
...顯示登錄失敗界面...
}
public void showLoginingView(){
...顯示登錄進(jìn)度條對話框...
}
public void dissLoginingView(){
...消失登錄進(jìn)度條對話框...
}
}
我們著重說下基礎(chǔ)設(shè)施BaseActivity:
因?yàn)橐粋€Activity是有可能包含多個Presenter的怔檩,所以需要在BaseActivity中是有必要把這些Presenter收集起來褪秀。
需要在BaseActivity的生命周期方法里面調(diào)用每個Presenter的相應(yīng)周期方法。
重構(gòu)以后的LoginActivity是不是很清爽薛训,只保留與view相關(guān)的邏輯媒吗。
小結(jié)重構(gòu)后的類結(jié)構(gòu)
重構(gòu)“萬能”LoginActivity到此結(jié)束,我們小結(jié)下重構(gòu)后的類結(jié)構(gòu):
- model層包含:LoginManager(登錄管理類)乙埃,UserEntity(用戶實(shí)體類闸英,主要使用在model層),UserDatabase(用戶數(shù)據(jù)表)介袜。
- presenter層包含:LoginConstract(登錄約定類甫何,組合ILoginView和ILoginPresenter),LoginPresenter(登錄presenter類),UserMapper(負(fù)責(zé)把model層的UserEntity轉(zhuǎn)化為view層使用的
UserInfo) - view層包含:BaseActivity(基礎(chǔ)類)米酬,LoginActivity(登錄Activity)沛豌,UserInfo(用戶信息類,主要使用在view層)
重構(gòu)感悟
疑惑
估計會有細(xì)心的朋友發(fā)現(xiàn)model層是LoginManager而不是像android clean architecture 中model層使用了respository,我個人覺得model層也沒必要這么嚴(yán)格的按respository的架構(gòu)方式來組織類結(jié)構(gòu)赃额,因?yàn)楸纠械卿浌δ軐?shí)在是太簡單了加派,所以就用最簡單的一個LoginManager類來供上層調(diào)用。
優(yōu)缺點(diǎn)
使用mvp重構(gòu)“萬能”Activity以后跳芳,帶來了以下好處:
- 類的組織結(jié)構(gòu)更清晰
- 每層可以進(jìn)行單獨(dú)的測試
- 類的可復(fù)用性更高
- 層與層的耦合性降低
- 可維護(hù)性更高
- 每個類盡量做到單一職責(zé)
但同時也帶來了一些缺點(diǎn)芍锦,比如創(chuàng)建的類多了很多,管理這些類的成本會增加飞盆。但是萬事萬物都有兩面性娄琉,就看利與弊的大小了次乓。我個人覺得mvp的利肯定是大于弊的,所以有必要采用這種架構(gòu)來設(shè)計你的app孽水。
提高生產(chǎn)效率
以上偽代碼中我沒有使用rxjava票腰,dagger2,假如把它們應(yīng)用于mvp中會讓你事半功倍女气,rxjava可以讓你在寫presenter層和model層時杏慰,可以讓presenter與model交互更簡單,可以是model層變的尤為的簡單比如從三大數(shù)據(jù)源取數(shù)據(jù)操作炼鞠,我們自己用代碼實(shí)現(xiàn)是可以的但是畢竟要花很多時間缘滥,但是用rxjava的一些操作符很容易做到。dagger2可以更好的幫助你進(jìn)行依賴注入, 可以參考下Android:dagger2讓你愛不釋手-基礎(chǔ)依賴注入框架篇
的介紹,還有鼎鼎有名的retrofit也是可以提高效率的谒主。
總結(jié)
本文我們了解了mvp以及每一層朝扼,以及使用mvp來重構(gòu)“萬能”Activity,其實(shí)每一層需要注意的東西還有很多霎肯,比如model層是最難寫的一層擎颖。希望我能在以后用幾篇文章來介紹每一層更多的細(xì)節(jié)。還有我現(xiàn)在正在用mvp做的一個項(xiàng)目姿现,等做完了我會上傳到github肠仪。歡迎大家指正。
本人微信:704451290