1.前言
-
MVP
模式是目前運(yùn)用最多的一種開(kāi)發(fā)模式蹂风,Presenter作為Model與View的橋梁,負(fù)責(zé)業(yè)務(wù)邏輯乾蓬、操作數(shù)據(jù)等工作。這樣把model與view實(shí)現(xiàn)了 分離(解耦合) 慎恒,有利于 結(jié)構(gòu)變得更簡(jiǎn)單 任内,以便開(kāi)發(fā)者更 容易管理與維護(hù) 自身的代碼。 - 雖然
MVP
具備那么多優(yōu)點(diǎn)融柬,但是它不是萬(wàn)能的死嗦,同樣存在一些 缺點(diǎn) 。 - 今天為大家分析一下主流大廠是如何解決這些缺點(diǎn)粒氧。
- 本文特點(diǎn):圖片多越除,字體少
- 文章中實(shí)例 linhaojian的Github
2.目錄
3.MVP模式
3.1 介紹
-
MVP
是從經(jīng)典的模式MVC演變而來(lái),它們的基本思想有相通的地方:Controller/Presenter負(fù)責(zé)邏輯的處理 外盯,Model提供數(shù)據(jù)摘盆,View負(fù)責(zé)顯示。
在這里插入圖片描述
3.2 作用
- 將 View 與 Model 分離饱苟,方便擴(kuò)展與維護(hù)孩擂。
- 方便 Presenter 進(jìn)行單元測(cè)試。
4.MVP缺點(diǎn)與解決
4.1 缺點(diǎn)
4.2 解決
- 4.2.1 內(nèi)存泄漏:
1)在Presenter傳入View實(shí)例引用時(shí)箱熬,通過(guò) 弱引用 進(jìn)行封裝类垦。
2)在Presenter中提供 綁定(attach) 與 解綁(detach) 函數(shù),以便調(diào)用者可以管理內(nèi)存釋放城须。
/**
* 將傳入的View接口實(shí)例蚤认,通過(guò)弱引用(WeakReference)把Presenter與View進(jìn)行綁定。
* @param aview 界面更新接口實(shí)例
*/
public void attach(Aview aview){
aviewWeakReference = new WeakReference<>(aview);
}
/**
* 將Presenter與View進(jìn)行解綁糕伐,并釋放內(nèi)存
*/
public void detach(){
if(aviewWeakReference!=null){
aviewWeakReference.clear();
aviewWeakReference = null;
}
}
- 4.2.2 每一個(gè)Presenter都需要編寫(xiě)相同 綁定砰琢、解綁 的代碼:
編寫(xiě)一個(gè)BasePresenter類,封裝 綁定赤炒、解綁的方法氯析。
public class BasePresenter<V> {
private WeakReference weakReference;
/**
* 將傳入的View接口實(shí)例,通過(guò)弱引用(WeakReference)把Presenter與View進(jìn)行綁定莺褒。
* @param v 界面更新接口實(shí)例
*/
public void attach(V v){
weakReference = new WeakReference<>(v);
}
/**
* 將Presenter與View進(jìn)行解綁掩缓,并釋放內(nèi)存
*/
public void detach(){
if(weakReference!=null){
weakReference.clear();
weakReference = null;
}
}
}
- 4.2.3 每一個(gè)Activity都需要 初始化 Presenter與調(diào)用其 綁定、解綁 的方法:
編寫(xiě)一個(gè)BaseActivity類遵岩,向子類提供Presenter初始化的抽象函數(shù)你辣;并在BaseActivity中onCreate()與onDestory中調(diào)用對(duì)應(yīng)Presenter類的attach()與detach()方法巡通。(提示:Fragment同理。)
/**
* BaseActivty:封裝Presenter的綁定與解綁方法舍哄,減少相同冗余代碼
* @param <V> View界面
* @param <P> Presenter
*/
public abstract class BaseAcitvity<V, P extends BasePresenter<V>> extends AppCompatActivity {
private P presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = createPresenter();
if(presenter!=null){
presenter.attach((V) this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(presenter!=null) {
presenter.detach();
presenter = null;
}
}
/**
* 創(chuàng)建繼承于BasePresenter的子類
* @return
*/
protected abstract P createPresenter();
}
- 4.2.4 Model都是以異步操作為主宴凉,因此可能按需編寫(xiě)多個(gè)不同功能的數(shù)據(jù)回調(diào)接口:
通過(guò)一些第三方的庫(kù)來(lái)處理該問(wèn)題。
發(fā)布事件/訂閱的框架:EventBus表悬、RxBus弥锄、Rxjava:不一樣的詮釋
萬(wàn)能接口庫(kù):Omnipotent
- 4.2.5 Presenter與View之間的耦合度高:
舉個(gè)例子:我們app中很多界面都使用了同一個(gè)Presenter,突然收到一個(gè)需求蟆沫,需要修改該P(yáng)resenter的構(gòu)造函數(shù)籽暇,那不是要每一個(gè)界面我都去修改一下代碼,多浪費(fèi)時(shí)間饭庞。通過(guò) Dagger2(依賴注入庫(kù)) 戒悠,它會(huì)幫助你完成new的工作。
- 4.2.6 一個(gè)View對(duì)應(yīng)多個(gè)Presenter
有時(shí)候有些界面是存在業(yè)務(wù)功能相同的情況(例如:請(qǐng)求的數(shù)據(jù)一樣)舟山,這時(shí)候就需要復(fù)用Presenter绸狐。
在BasePresenter添加一個(gè)列表管理需要復(fù)用的Presenter對(duì)象。
public class BasePresenter<V> {
private WeakReference weakReference;
private WeakReference<HashMap<String,BasePresenter>> weakReferenceListPresenter;
public BasePresenter(){
weakReferenceListPresenter = new WeakReference(new HashMap<>());
}
/**
* 將傳入的View接口實(shí)例累盗,通過(guò)弱引用(WeakReference)把Presenter與View進(jìn)行綁定寒矿。
* @param v 界面更新接口實(shí)例
*/
public void attach(V v){
weakReference = new WeakReference<>(v);
}
/**
* 將Presenter與View進(jìn)行解綁,并釋放內(nèi)存
*/
public void detach(){
detachPresenter();
if(weakReference!=null){
weakReference.clear();
weakReference = null;
}
}
/**
* 添加復(fù)用的Presenter實(shí)例幅骄,并將View與它們進(jìn)行綁定
* @param c
* @param p
* @param <P>
*/
public <P extends BasePresenter> void addPresenter(Class<P> c,P p){
if(weakReferenceListPresenter!=null){
(weakReferenceListPresenter.get()).put(c.getName(),p);
p.attach(weakReference.get());
}
}
/**
* 通過(guò)類獲取對(duì)應(yīng)的Presenter對(duì)象
* @param c
* @param <P>
* @return
*/
public <P extends BasePresenter> P getPresenter(Class<P> c){
if(weakReferenceListPresenter!=null){
return (P) (weakReferenceListPresenter.get()).get(c.getName());
}
return null;
}
/**
* View與其他Presenter進(jìn)行解綁
*/
private void detachPresenter(){
if(weakReferenceListPresenter!=null){
HashMap<String,BasePresenter> map = weakReferenceListPresenter.get();
if(map!=null){
for(String name : map.keySet()){
map.get(name).detach();
}
}
}
}
5.總結(jié)
- 從 4.2.4~4.2.5 中可以發(fā)現(xiàn)劫窒,中間者 可以解決重復(fù)編寫(xiě)數(shù)據(jù)回調(diào)接口、耦合 的問(wèn)題拆座。
- 到此主巍,
MVP
設(shè)計(jì)模式就分析完畢,希望能在開(kāi)發(fā)過(guò)程中幫助大家挪凑。 - 如果喜歡我的分享孕索,可以點(diǎn)擊 關(guān)注 或者 贊,你們支持是我分享的最大動(dòng)力 躏碳。
- linhaojian的Github
歡迎關(guān)注linhaojian_CSDN博客或者linhaojian_簡(jiǎn)書(shū)搞旭!
不定期分享關(guān)于安卓開(kāi)發(fā)的干貨。
寫(xiě)技術(shù)文章初心
- 技術(shù)知識(shí)積累
- 技術(shù)知識(shí)鞏固
- 技術(shù)知識(shí)分享
- 技術(shù)知識(shí)交流