內(nèi)存泄漏分析
最近在學(xué)習(xí)MVP架構(gòu)模式中吴汪,一直模糊與MVP模式真正能帶來什么惠窄,我們能從中收獲什么。淺顯地來說代碼分層漾橙,易于重構(gòu)和維護(hù)杆融,代碼結(jié)構(gòu)分析。但真正在使用過程中霜运,感覺又是可有可無的東西脾歇。接下來是我這一天學(xué)習(xí)查閱資料的體會(huì)。
Android項(xiàng)目性能優(yōu)化中有個(gè)必須關(guān)注的點(diǎn)是內(nèi)存泄漏淘捡,下面篇幅不在細(xì)說內(nèi)存泄漏工具檢測(cè)藕各,而在重點(diǎn)說明在實(shí)際場(chǎng)景中造成內(nèi)存泄漏的原因以及解決方案和MVP模式的好處。
-
內(nèi)存泄漏常見場(chǎng)景
1.資源對(duì)象沒關(guān)閉
比如Cursor游標(biāo)File文件等焦除,我們?cè)诓皇褂玫臅r(shí)候應(yīng)該關(guān)閉它激况,以便它們的緩沖及時(shí)回收內(nèi)存。面對(duì)這一情況一定要養(yǎng)成關(guān)閉資源的習(xí)慣膘魄,因?yàn)檫@種造成泄漏的是長(zhǎng)時(shí)間大量操作情況下才會(huì)復(fù)現(xiàn)乌逐,會(huì)為以后的測(cè)試和排查帶來困難和風(fēng)險(xiǎn)
2.構(gòu)造Adapter適配器時(shí),沒有使用緩存的contentView
3.試著使用Application的Context代替Activity的Context
Application的Context的生命周期維持整個(gè)應(yīng)用创葡,若在使用過程中持有了該Context浙踢,那么在回收過程中因?yàn)樵揅ontext的生命周期過長(zhǎng),會(huì)導(dǎo)致持有對(duì)象無法回收
4.注冊(cè)沒取消
如廣播灿渴、服務(wù)等洛波,即使程序結(jié)束了,但是別的引用程序可能仍然對(duì)我們的程序的某個(gè)對(duì)象的引用骚露,泄漏的內(nèi)存仍不能被回收蹬挤。調(diào)用廣播registerReceiver后記得要調(diào)用unregisterReceiver
5.集合對(duì)象沒清空
若在單例中維護(hù)集合對(duì)象,我們通常把一些對(duì)象引用加入到集合中荸百,當(dāng)我們不需要該對(duì)象時(shí)闻伶,需要把它的引用從集合中移除,避免集合對(duì)象占用過多內(nèi)存
6.內(nèi)部類持有外部類導(dǎo)致
在外部類中定義內(nèi)部類够话,如定義一個(gè)線程或者Handler蓝翰,當(dāng)線程執(zhí)行耗時(shí)操作時(shí)關(guān)閉Activity,重復(fù)該操作女嘲,由于線程持有Activity對(duì)象畜份,導(dǎo)致Activity對(duì)象無法被回收。
線程耗時(shí)這種操作是無法避免的欣尼,這時(shí)就可以使用MVP模式了爆雹,把耗時(shí)操作放入Presenter中執(zhí)行停蕉,可以定義static靜態(tài)Presenter,讓其不持有Activity對(duì)象钙态,這是一種解決思路慧起,但我們可以通過別人對(duì)MVP模式的封裝來優(yōu)化內(nèi)存泄漏的問題。
備注:AsyncTask和RxJava處理異步時(shí)册倒,cancle或者unsubscribe僅是不觸發(fā)onPostExecute或onNext蚓挤。異步操作還是在跑的,只是沒通知回調(diào)而已驻子,這個(gè)是以前的誤區(qū)灿意。所以這種內(nèi)存消耗是無法避免的,我們的優(yōu)化點(diǎn)就在于避免不必要的異步耗時(shí)請(qǐng)求
通常意義上Presenter都有持有View對(duì)象崇呵,而View經(jīng)常是Activity和Fragment來扮演缤剧,那這不就是矛盾了嗎?在Presenter會(huì)執(zhí)行網(wǎng)絡(luò)請(qǐng)求這些耗時(shí)操作域慷,請(qǐng)求結(jié)束后會(huì)讓View作出反饋荒辕,那當(dāng)Activity或者Fragment釋放時(shí)由于Presenter持有對(duì)象那就會(huì)Acitivity或者Fragment釋放不了可能導(dǎo)致內(nèi)存泄露的發(fā)生。那么怎么解決這個(gè)問題呢芒粹?可以在View onDestroy銷毀時(shí)執(zhí)行Presenter解綁View操作兄纺,讓View置null,通知GC釋放View化漆。當(dāng)View重新置于前臺(tái)時(shí)讓Presenter重新綁定估脆。
Nucles框架
下面會(huì)花一定篇幅來介紹MVP封裝庫Nucles,而Nucles是什么呢座云,有什么好處疙赠?
-
特性總結(jié)
1.它支持在View/Fragment/Activity的Bundle中保存/恢復(fù)Presenter的狀態(tài),一個(gè)Presenter可以保存它的請(qǐng)求參數(shù)到bundles中朦拖,以便之后重啟它們
2.它允許一個(gè)View實(shí)例持有多個(gè)Presenter對(duì)象
3.快速實(shí)現(xiàn)View和Presenter的綁定
4.提供線程的基類以便復(fù)用
5.支持在進(jìn)程重啟后圃阳,自動(dòng)重新發(fā)起請(qǐng)求,在onDestroy方法中璧帝,自動(dòng)退訂RxJava訂閱
6.相當(dāng)簡(jiǎn)潔 - 代碼層總結(jié)
RequiesPresenter:自定義注解捍岳,方便工廠加工Presenter實(shí)例
PresenterStorage:Presenter存儲(chǔ)單例,方便View重啟恢復(fù)Presenter
RxPresenter:實(shí)現(xiàn)對(duì)業(yè)務(wù)的封裝睬隶,對(duì)業(yè)務(wù)做解綁操作等
PresenterLifecycleDelegate:Presenter生命周期委托锣夹,其中的方法對(duì)應(yīng)View的生命周期。如onSaveInstanceState保存Presenter相關(guān)至View的bundlestate苏潜,以便onRestoreInstanceState時(shí)恢復(fù)
NucleusActivity/NucleusFragment/NucleusLayout:持有PresenterLifecycleDelegate對(duì)象银萍,統(tǒng)一PresenterLifecycleDelegate管理Presenter生命周期
Delivery相關(guān):涉及RxJava部分,通常是建議Presenter不直接操作View恤左,Delivery實(shí)現(xiàn)Observable<數(shù)據(jù)源>->Observable<View,數(shù)據(jù)源>轉(zhuǎn)換贴唇,動(dòng)態(tài)操作View
通過一張圖來作分析:
<View,T>分別對(duì)應(yīng)View對(duì)象和數(shù)據(jù)源搀绣。Observable<T>是如通過Retrofit網(wǎng)絡(luò)請(qǐng)求到的數(shù)據(jù)源操作。我們需要將數(shù)據(jù)源操作轉(zhuǎn)換成對(duì)View和數(shù)據(jù)源兩者的操作戳气。從中而知我們需要封裝個(gè)Delivery對(duì)象存放View和數(shù)據(jù)源链患,然后將網(wǎng)絡(luò)請(qǐng)求轉(zhuǎn)換成對(duì)Delivery。最終subscribe訂閱后讓Delivery內(nèi)部處理特定邏輯物咳。那么View對(duì)象是從哪里獲取到的呢锣险,答案就在構(gòu)造參數(shù)Observable<View> view對(duì)象中蹄皱,這個(gè)對(duì)象是聲明在RxPresenter中的private final BehaviorSubject<View> views = BehaviorSubject.create();
最后附上例子:
https://github.com/hhhhskfk/oschina-mvp
RxJava介紹
BehaviorSubject:相當(dāng)于Observable或者Subscriber览闰,這個(gè)作用是當(dāng)被訂閱后執(zhí)行onNext執(zhí)行具體操作后,會(huì)優(yōu)先發(fā)送一個(gè)默認(rèn)值
SubscriptionList:Subscription列表巷折,管理列表中訂閱的解除
Observable.first():僅在第一次訂閱中執(zhí)行
combineLatest():作用于最近發(fā)射的數(shù)據(jù)項(xiàng):如果Observable1發(fā)射了A并且Observable2發(fā)射了B和C压鉴,combineLatest()將會(huì)分組處理AB和AC
具體RxJava干貨請(qǐng)看這里
Awesome-RxJava
RxJava resources
Blog
給 Android 開發(fā)者的 RxJava 詳解 -強(qiáng)烈推薦 扔物線的文章 講解非常詳細(xì)
NotRxJava懶人專用指南 -這篇入門極力推薦,手把手锻拘,深入淺出教你實(shí)現(xiàn)一個(gè)簡(jiǎn)易的RxJava庫油吭,更好的理解RxJava的實(shí)現(xiàn)思路
如何升級(jí)到RxAndroid1.0 -適合使用Rx 0.x版本的用戶升級(jí)的時(shí)候參考
開發(fā)者前線翻譯的一系列很贊的教程
那些年我們錯(cuò)過的響應(yīng)式編程 -非常棒的講解響應(yīng)式編程的文章。
當(dāng)復(fù)仇者聯(lián)盟遇上Dragger2署拟、RxJava和Retrofit的巧妙結(jié)合
一些不錯(cuò)的介紹操作符的文章
RxMarbles-Interactive diagrams of Rx Observables
一些不錯(cuò)的翻譯文章
一些原理分析的文章
Test
【譯】RxJava Essentials 中文翻譯版 -Ivan.Morgillo所寫一書的中文翻譯版本
【譯】RxJava Essentials 中文翻譯版 -Ivan.Morgillo所寫一書的中文翻譯版本
App
android-gfycat -Android application that loads gifs via gfycat for efficiency's sake
JakeWharton/u2020 -Jake大神的項(xiàng)目婉宰,里面有RxJava和Retrofit一起使用的例子
Avengers - 一個(gè)使用Retrofit+RxJava+MVP的app
TranslateApp - 一個(gè)使用 MVP+Dagger2+RxJava+Retrofit的實(shí)現(xiàn)手機(jī)端『劃詞翻譯』功能的App - 咕咚翻譯
AppPlus - 一個(gè)可以用于傳送Apk文件,提取APK文件等的工具軟件推穷。
rx-android-architecture -Android中使用Rx的一種架構(gòu)
android-boilerplate -使用RxJava+Retrofit+MVP的app心包,并了結(jié)合詳細(xì)的測(cè)試用例
RxJavaApp -用于學(xué)習(xí)RxJava操作符的APP
Example
learnrxjava -RxJava例子
Intro-To-RxJava -RxJava實(shí)例入門
MovieGuide-An Android app that showcases the MVP pattern and RxJava
RxWeather
-Architecting Android with RxJavaRxBlur-用RxJava處理和操作高斯模糊效果的簡(jiǎn)單用例。
Library
rx-preferences -使SharedPreferences支持RxJava
RxAndroid -RxJava的Android拓展
RxAndroid -RxJava的Android拓展
RxLifecycle -幫助使用了RxJava的安卓應(yīng)用控制生命周期
RxBinding -安卓UI控件的RxJava綁定API
storio -支持RxJava的數(shù)據(jù)庫
retrofit -支持RxJava的網(wǎng)絡(luò)請(qǐng)求庫
sqlbrite -支持RxJava的sqlite數(shù)據(jù)庫
RxPermissions -RxJava實(shí)現(xiàn)的Android運(yùn)行時(shí)權(quán)限控制
xBus -簡(jiǎn)潔的EventBus實(shí)現(xiàn)