Android開發:淺談MVP模式應用與記憶體洩漏
最近博主開始在專案中實踐MVP模式,卻意外發現記憶體洩漏比較嚴重,但卻很少人談到這個問題,促使了本文的釋出,本文假設讀者已瞭解MVP架構。
MVP簡介
M-Modle,資料,邏輯操作層,資料獲取,資料持久化儲存。比如網路操作,資料庫操作
V-View,介面展示層,Android中的具體體現為Activity,Fragment
P-Presenter,中介者,連線Modle,View層,同時持有modle引用和view介面引用
上圖摘自阮一峰大神部落格:MVC,MVP 和 MVVM 的圖示
注:有別於MVC,Activity,Fragment通常被用作Controller和View使用,加重了它的職責。在MVP中,Activity,Fragment僅用做View層展示
示例程式碼
Modle層操作
public class TestModle implements IModle{
private CallbackListener callback;
public TestModle(CallbackListener callback) {
this.callback = callback;
}
public interface CallbackListener {
void onGetData(String data);
}
public void getData () {
new Thread() {
public void run() {
callback.onGetData("返回的資料");
}
}.start();
}
}
View層
// 抽象的view層
public interface TestViewInterf extends IView {
void onGetData(String data);
}
// 具體的View層
public class MainActivity extends Activity implements TestViewInterf{
private TestPresenter mTestPresenter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// view層將獲取資料的任務委派給中介者presenter,並傳入自身例項物件,實現TestViewInterf介面
mTestPresenter = new TestPresenter(this);
mTestPresenter.getData();
}
@Override
public void onGetData(String data) {
// View層只做資料展示
showToast(data);
}
private void showToast(String toast) {
Toast.makeText(this, toast, Toast.LENGTH_LONG).show();
}
}
Presenter中介者
public class TestPresenter implements IPresenter{
IModle modle;
IView view;
public TestPresenter(IView view) {
this.view = view;
}
public void getData() {
// 獲取資料的操作實際在Modle層執行
modle = new TestModle(new CallbackListener() {
public void onGetData(String data) {
if (view != null) {
view.onGetData(data);
}
}
});
modle.getData();
}
}
根據OOP思想,Java程式碼最好面向介面,抽象程式設計,這樣才能給符合OCP原則。上述示例程式碼省略了更加抽象的介面IModle,IView,IPresenter,並且實際MVP實踐中通常會引入泛型使其更具擴充套件性。
記憶體洩露問題
由上可見,Presenter中持有View介面物件,這個介面物件實際為MainActivity.this,Modle中也同時擁有Presenter物件例項,當MainActivity要銷燬時,Presenter中有Modle在獲取資料,那麼問題來了,這個Activity還能正常銷燬嗎?
答案是不能!
當Modle在獲取資料時,不做處理,它就一直持有Presenter物件,而Presenter物件又持有Activity物件,這條GC鏈不剪斷,Activity就無法被完整回收。
換句話說:Presenter不銷燬,Activity就無法正常被回收。
解決MVP的記憶體洩露
Presenter在Activity的onDestroy方法回撥時執行資源釋放操作,或者在Presenter引用View物件時使用更加容易回收的軟引用,弱應用。
比如示例程式碼:
Activity
@Override
public void onDestroy() {
super.onDestroy();
mPresenter.destroy();
mPresenter = null;
}
Presenter
public void destroy() {
view = null;
if(modle != null) {
modle.cancleTasks();
modle = null;
}
}
Modle
public void cancleTasks() {
// TODO 終止執行緒池ThreadPool.shutDown(),AsyncTask.cancle(),或者呼叫框架的取消任務api
}
個人總結
因為面向MVP介面程式設計,可適應需求變更,所以MVP適用於比較大的專案;因為其簡化了Activity和Fragmnt的職責,可大大減少View層的程式碼量,比起MVC中Activity,Fragment動不動上千行的程式碼量,簡直優雅!
做完以上操作,由於MVP引起的記憶體洩露就差不多解決了,祝大家擼碼愉快!歡迎留言區交流指正。