Android開發(fā):淺談MVP模式應(yīng)用與內(nèi)存泄漏問題解決
最近博主開始在項(xiàng)目中實(shí)踐MVP模式,卻意外發(fā)現(xiàn)內(nèi)存泄漏比較嚴(yán)重,但卻很少人談到這個(gè)問題,促使了本文的發(fā)布,本文假設(shè)讀者已了解MVP架構(gòu)。
MVP簡(jiǎn)介
M-Modle,數(shù)據(jù),邏輯操作層,數(shù)據(jù)獲取,數(shù)據(jù)持久化保存。比如網(wǎng)絡(luò)操作,數(shù)據(jù)庫(kù)操作
V-View,界面展示層,Android中的具體體現(xiàn)為Activity,F(xiàn)ragment
P-Presenter,中介者,連接Modle,View層,同時(shí)持有modle引用和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("返回的數(shù)據(jù)");
}
}.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層將獲取數(shù)據(jù)的任務(wù)委派給中介者presenter,并傳入自身實(shí)例對(duì)象,實(shí)現(xiàn)TestViewInterf接口
mTestPresenter = new TestPresenter(this);
mTestPresenter.getData();
}
@Override
public void onGetData(String data) {
// View層只做數(shù)據(jù)展示
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() {
// 獲取數(shù)據(jù)的操作實(shí)際在Modle層執(zhí)行
modle = new TestModle(new CallbackListener() {
public void onGetData(String data) {
if (view != null) {
view.onGetData(data);
}
}
});
modle.getData();
}
}
根據(jù)OOP思想,Java應(yīng)面向接口編程,這樣才能給符合OCP原則。上述示例代碼省略了更加抽象的接口IModle,IView,IPresenter,并且實(shí)際MVP實(shí)踐中通常會(huì)引入泛型使其更具擴(kuò)展性。
Google已提供了相關(guān)示例代碼,并在MVP中增加了一個(gè)約束者:Contract,它的作用是定義各個(gè)模塊的MVP接口。
google MVP sample code:https://github.com/googlesamples/android-architecture
內(nèi)存泄露問題
由上可見,Presenter中持有View接口對(duì)象,這個(gè)接口對(duì)象實(shí)際為MainActivity.this,Modle中也同時(shí)擁有Presenter對(duì)象實(shí)例,當(dāng)MainActivity要銷毀時(shí),Presenter中有Modle在獲取數(shù)據(jù),那么問題來了,這個(gè)Activity還能正常銷毀嗎?
答案是不能!
當(dāng)Modle在獲取數(shù)據(jù)時(shí),不做處理,它就一直持有Presenter對(duì)象,而Presenter對(duì)象又持有Activity對(duì)象,這條GC鏈不剪斷,Activity就無法被完整回收。
換句話說:Presenter不銷毀,Activity就無法正常被回收。
解決MVP的內(nèi)存泄露
Presenter在Activity的onDestroy方法回調(diào)時(shí)執(zhí)行資源釋放操作,或者在Presenter引用View對(duì)象時(shí)使用更加容易回收的軟引用,弱應(yīng)用。
比如示例代碼:
Activity
@Override
public void onDestroy() {
super.onDestroy();
mPresenter.destroy();
}
Presenter
public void destroy() {
view = null;
if(modle != null) {
modle.cancleTasks();
}
}
Modle
public void cancleTasks() {
// TODO 終止線程池ThreadPool.shutDown(),AsyncTask.cancle(),或者調(diào)用框架的取消任務(wù)api
}
個(gè)人總結(jié)
因?yàn)槊嫦騇VP接口編程,可適應(yīng)需求變更,所以MVP適用于比較大的項(xiàng)目;因?yàn)槠浜?jiǎn)化了Activity和Fragmnt的職責(zé),可大大減少View層的代碼量,比起MVC中Activity,F(xiàn)ragment動(dòng)不動(dòng)上千行的代碼量,簡(jiǎn)直優(yōu)雅!
做完以上操作,由于MVP引起的內(nèi)存泄露就差不多解決了,以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android拼圖游戲 玩轉(zhuǎn)從基礎(chǔ)到應(yīng)用手勢(shì)變化
這篇文章主要介紹了Android拼圖游戲的實(shí)現(xiàn)方法,教大家玩轉(zhuǎn)從基礎(chǔ)到應(yīng)用手勢(shì)變化,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
Android ListView實(shí)現(xiàn)圖文列表顯示
這篇文章主要為大家詳細(xì)介紹了Android ListView實(shí)現(xiàn)圖文列表顯示,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
Android 中Volley二次封裝并實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求緩存
這篇文章主要介紹了Android 中Volley二次封裝并實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求緩存的相關(guān)資料,希望通過本文能幫助到大家,徹底會(huì)使用Volley,需要的朋友可以參考下2017-09-09
Kotlin中的handler如何避免內(nèi)存泄漏詳解
Handler,我們已經(jīng)相當(dāng)熟悉了,而且經(jīng)常用得不亦樂乎,但就是因?yàn)樘煜ち?,才?huì)偶爾被它反捅一刀,血流不止,下面這篇文章主要給大家介紹了關(guān)于Kotlin中handler如何避免內(nèi)存泄漏的相關(guān)資料,需要的朋友可以參考下。2017-12-12

