前言
在暑假的時(shí)候?qū)W習(xí)了一遍mvp開(kāi)發(fā)模式在android中的運(yùn)用。那個(gè)時(shí)候?qū)W的時(shí)候確實(shí)覺(jué)得mvp模式做安卓開(kāi)發(fā)特別清晰,代碼模塊分的特別清楚糟袁。但是在自己寫(xiě)demo的時(shí)候還是把自己有點(diǎn)繞暈了。因?yàn)閙vp模式運(yùn)用了大量的接口(面向接口編程)來(lái)實(shí)現(xiàn)view和model層的解耦。那時(shí)候甚至連設(shè)計(jì)模式都沒(méi)看攒驰,所以一下子接觸這種抽象的設(shè)計(jì)模式有點(diǎn)不適應(yīng)。雖然說(shuō)google的data-binding的不斷完善會(huì)導(dǎo)致安卓上面mvvm模式越來(lái)越火故爵,但是我覺(jué)得設(shè)計(jì)模式嘛玻粪,學(xué)習(xí)一下沒(méi)有壞處,可以提升自己的理解力诬垂。這篇博客主要講一種mvp的一種新嘗試(將activity, fragment, adapter作為presenter)劲室。
MVP
mvp模式與mvc模式最大的差別就是,它將view層跟model實(shí)現(xiàn)完全解耦结窘。所有的數(shù)據(jù)交互都在presenter層中很洋。view,model和presenter的交互通過(guò)接口,view和model的交互通過(guò)presenter隧枫。解耦的好處就是視圖層和數(shù)據(jù)層兩者互不影響喉磁,所有的邏輯都在presenter中,他作為一個(gè)中間層可以給多個(gè)view來(lái)使用官脓。完全通過(guò)接口來(lái)解耦可以提高代碼維護(hù)度协怒。
而mvc模式則是視圖層可以通過(guò)control與數(shù)據(jù)層交互也可以直接跳過(guò)control和數(shù)據(jù)層直接交互。這樣大多數(shù)時(shí)候會(huì)在view層里面new出model/bean的對(duì)象來(lái)卑笨。這樣就把兩者耦合在了一起孕暇。
傳統(tǒng)mvp
傳統(tǒng)的mvp模式是將activity或者fragment作為view層,將所有的邏輯代碼抽出到presenter(一個(gè)java類)赤兴。這是我暑假寫(xiě)的一個(gè)demo源碼 傳統(tǒng)mvp demo 芭商。
可以通過(guò)我的項(xiàng)目分包看出來(lái),每一個(gè)類實(shí)現(xiàn)接口搀缠,通過(guò)接口來(lái)進(jìn)行抽象解耦铛楣,以及數(shù)據(jù)交互。
一種新思想
這個(gè)思想也是通過(guò)github上面一個(gè)翻譯的文章看來(lái)的艺普。因?yàn)閍ctivity中包含著context簸州, intent鉴竭,獲得系統(tǒng)服務(wù)等等,如果把a(bǔ)ctivity作為視圖層就應(yīng)該避免這些業(yè)務(wù)邏輯岸浑。所以將activity僅僅作為視圖層有點(diǎn)發(fā)揮不出他的真正價(jià)值搏存。所以我們考慮把a(bǔ)ctivity,fragment矢洲,adapter來(lái)作為presenter處理邏輯璧眠,用java類文件來(lái)作為視圖層。并且這樣做了之后读虏,我感覺(jué)代碼的清晰度是有提升的责静。這是我寫(xiě)的demo源碼:新mvp demo 。
大概思路是用一個(gè)抽象類來(lái)抽出activity中必不可少的ui代碼(比如setContentView()以及初始化各種控件)盖桥。然后每一個(gè)view類文件實(shí)現(xiàn)擴(kuò)展了view層基接口的接口灾螃,這樣做的目的是為了實(shí)現(xiàn)view和baseacitivty之間的解耦。(這個(gè)確實(shí)倒騰了很久揩徊,因?yàn)槲腋杏X(jué)原文章的代碼有問(wèn)題)腰鬼。之后在抽象類里面去通過(guò)presenter返回的view文件類型,用反射獲得對(duì)象并進(jìn)行view的渲染塑荒。然后再在presenter中去處理邏輯熄赡。看代碼吧齿税!
/**
* Created by Zane on 15/12/5.
* 用于抽出activity中對(duì)于ui的操作代碼
* 弄出兩個(gè)抽象方法來(lái)保證生命周期同步
*/
public abstract class BasePresentActivity<X extends V, V extends Vu> extends AppCompatActivity{
protected V vu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
vu = getVuClass().newInstance();
vu.init(getLayoutInflater(), null);
setContentView(vu.getView());
onBindVu();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
onDestroyVu();
vu = null;
super.onDestroy();
}
protected abstract Class<X> getVuClass();
protected void onBindVu(){};
protected void onDestroyVu() {};
}
首先解釋這個(gè)抽象類的兩個(gè)泛型本谜。Vu是view層的基接口,代碼如下:
/**
* Created by Zane on 15/12/5.
* view類的超類
*/
public interface Vu {
void init(LayoutInflater inflater, ViewGroup container);
View getView();
}
可以看到有兩個(gè)方法偎窘,一個(gè)用來(lái)進(jìn)行view渲染,一個(gè)是返回根視圖溜在。而泛型里面的V就是擴(kuò)展了Vu的第二層接口陌知。最后X就是實(shí)現(xiàn)了第二層接口的view類文件。這樣做的目的就是做到解耦掖肋,防止我用傳入的類文件去實(shí)例化類文件仆葡,這里應(yīng)該是去實(shí)例化接口。(用X的對(duì)象去實(shí)例化V)
然后再看onBindVu()和onDestoryVu()方法志笼,這個(gè)方法是在繼承了這個(gè)抽象類的presenter里面去實(shí)現(xiàn)的沿盅,目的是為了達(dá)到生命周期同步。
getVuClass()方法就是要獲得這個(gè)presenter對(duì)應(yīng)的view類文件類型纫溃。
/**
* Created by Zane on 15/12/5.
* 為了使view類和present類解藕
*/
public interface VuLoginActivity extends Vu{
Button getButtonLogin();
Button getButtonClear();
EditText getEditTextAccount();
EditText getEditTextPassword();
void clearText();
}
這就是擴(kuò)展了Vu接口的第二層接口腰涧。看到我添加了幾個(gè)方法紊浩。
/**
* Created by Zane on 15/12/5.
*/
public class LoginActivityViewImpl implements VuLoginActivity{
protected View view;
protected Button buttonLogin;
protected Button buttonClear;
protected EditText account;
protected EditText password;
@Override
public void init(LayoutInflater inflater, ViewGroup container) {
view = inflater.inflate(R.layout.activity_main, container, false);
buttonLogin = (Button)view.findViewById(R.id.button_login);
buttonClear = (Button)view.findViewById(R.id.button_clear);
account = (EditText)view.findViewById(R.id.account);
password = (EditText)view.findViewById(R.id.password);
}
@Override
public View getView() {
return view;
}
@Override
public Button getButtonLogin() {
return buttonLogin;
}
@Override
public Button getButtonClear() {
return buttonClear;
}
@Override
public EditText getEditTextAccount() {
return account;
}
@Override
public EditText getEditTextPassword() {
return password;
}
@Override
public void clearText() {
account.setText("");
password.setText("");
}
}
這里代碼也很簡(jiǎn)單啦窖铡!
public class MainActivity extends BasePresentActivity<LoginActivityViewImpl, VuLoginActivity> {
@Override
protected void onBindVu() {
final User user = new User();
vu.getButtonLogin().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String userName = vu.getEditTextAccount().getText().toString();
String password = vu.getEditTextPassword().getText().toString();
Toast.makeText(MainActivity.this, userName, Toast.LENGTH_SHORT).show();
if(userName.equals(user.getUserName()) && password.equals(user.getPassword())) {
Intent intent = new Intent(MainActivity.this, LoginSuccessActivity.class);
intent.putExtra("username", userName);
startActivity(intent);
}else {
Toast.makeText(MainActivity.this, "錯(cuò)誤", Toast.LENGTH_SHORT).show();
}
}
});
vu.getButtonClear().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
vu.clearText();
}
});
}
@Override
protected void onDestroyVu() {
super.onDestroyVu();
}
@Override
protected Class<LoginActivityViewImpl> getVuClass() {
return LoginActivityViewImpl.class;
}
}
這個(gè)就是presenter疗锐。看到我在對(duì)應(yīng)的生命周期里面做了邏輯處理费彼,并且返回他對(duì)應(yīng)的view類文件滑臊。
結(jié)束語(yǔ)
MVP模式確實(shí)給項(xiàng)目維護(hù)帶來(lái)了一些便捷,但是也發(fā)現(xiàn)箍铲,相對(duì)于小的項(xiàng)目會(huì)導(dǎo)致你的代碼量迅速膨脹雇卷。所有很多人弄一些mvp的開(kāi)發(fā)框架。確實(shí)我自己也想用這種新思路來(lái)倒騰一個(gè)颠猴。但是對(duì)于大型項(xiàng)目关划,這樣的代碼膨脹并不算什么,帶來(lái)的好處絕對(duì)優(yōu)于壞處芙粱。這次學(xué)習(xí)又鞏固了一下我的設(shè)計(jì)模式祭玉。以一句話結(jié)尾:面對(duì)接口編程, 避免面對(duì)實(shí)現(xiàn)編程
未經(jīng)博主同意春畔,不得轉(zhuǎn)載該篇文章