如何進(jìn)行單元測(cè)試膛堤,如何保證 App 穩(wěn)定 漓拾?
要測(cè)試 Android 應(yīng)用程序乌企,通常會(huì)創(chuàng)建以下類(lèi)型自動(dòng)單元測(cè)試
- 本地測(cè)試:只在本地機(jī)器 JVM 上運(yùn)行虑润,以最小化執(zhí)行時(shí)間,這種單元測(cè)試不依賴于 Android 框架逛犹,或者即使有依賴端辱,也很方便使用模擬框架來(lái)模擬依賴,以達(dá)到隔離 Android 依賴的目的虽画,模擬框架如Google 推薦的 Mockito舞蔽;
- 檢測(cè)測(cè)試:真機(jī)或模擬器上運(yùn)行的單元測(cè)試,由于需要跑到設(shè)備上码撰,比較慢渗柿,這些測(cè)試可以訪問(wèn)儀器(Android 系統(tǒng))信息,比如被測(cè)應(yīng)用程序的上下文脖岛,一般地朵栖,依賴不太方便通過(guò)模擬框架模擬時(shí)采用這種方式;
注意:?jiǎn)卧獪y(cè)試不適合測(cè)試復(fù)雜的 UI 交互事件
App 的穩(wěn)定主要決定于整體的系統(tǒng)架構(gòu)設(shè)計(jì)柴梆,同時(shí)也不可忽略代碼編程的細(xì)節(jié)規(guī)范陨溅,正所謂“千里之堤,潰于蟻穴”绍在,一旦考慮不周门扇,看似無(wú)關(guān)緊要的代碼片段可能會(huì)帶來(lái)整體軟件系統(tǒng)的崩潰雹有,所以上線之前除了自己本地化測(cè)試之外還需要進(jìn)行 Monkey 壓力測(cè)試
少部分面試官可能會(huì)延伸,如 Gradle 自動(dòng)化測(cè)試臼寄、機(jī)型適配測(cè)試等霸奕。
Apk 的大小如何壓縮
- 減少 res,壓縮圖文文件
- 圖片文件壓縮是針對(duì) jpg 和 png 格式的圖片吉拳。我們通常會(huì)放置多套不同分辨率的圖片以適配不同的屏幕质帅,這里可以進(jìn)行適當(dāng)?shù)膭h減。在實(shí)際使用中留攒,只保留一到兩套就足夠了(保留一套的話建議保留xxhdpi煤惩,兩套的話就加上 hdpi),然后再對(duì)剩余的圖片進(jìn)行壓縮(jpg 采用優(yōu)圖壓縮炼邀,png 嘗試采用pngquant 壓縮)
- 減少 dex 文件大小
- 添加資源混淆
- shrinkResources 為 true 表示移除未引用資源盟庞,和代碼壓縮協(xié)同工作。
- minifyEnabled 為 true 表示通過(guò) ProGuard 啟用代碼壓縮汤善,配合 proguardFiles 的配置對(duì)代碼進(jìn)行混淆并移除未使用的代碼什猖。
- 代碼混淆在壓縮 apk 的同時(shí),也提升了安全性红淡。
- 減少 lib 文件大小
- 由于引用了很多第三方庫(kù)不狮,lib 文件夾占用的空間通常都很大,特別是有 so 庫(kù)的情況下在旱。很多 so 庫(kù)會(huì)同時(shí)引入 armeabi摇零、armeabi-v7a 和 x86 這幾種類(lèi)型,這里可以只保留 armeabi 或 armeabi-v7a 的其中一個(gè)就可以了桶蝎,實(shí)際上微信等主流 app 都是這么做的驻仅。
- 只需在 build.gradle 直接配置即可,NDK 配置同理
如何通過(guò) Gradle 配置多渠道包登渣?
- 首先要了解設(shè)置多渠道的原因噪服。在安裝包中添加不同的標(biāo)識(shí),配合自動(dòng)化埋點(diǎn)胜茧,應(yīng)用在請(qǐng)求網(wǎng)絡(luò)的時(shí)候攜帶渠道信息粘优,方便后臺(tái)做運(yùn)營(yíng)統(tǒng)計(jì),比如說(shuō)統(tǒng)計(jì)我們的應(yīng)用在不同應(yīng)用市場(chǎng)的下載量等信息
- 這里以友盟統(tǒng)計(jì)為例
-
首先在 manifest.xml 文件中設(shè)置動(dòng)態(tài)渠道變量:
-
接著在 app 目錄下的 build.gradle 中配置 productFlavors呻顽,也就是配置打包的渠道:
最后在編輯器下方的 Teminal 輸出命令行
執(zhí)行./gradlew assembleRelease
雹顺,將會(huì)打出所有渠道的 release 包;
執(zhí)行./gradlew assembleVIVO
廊遍,將會(huì)打出 VIVO 渠道的 release 和 debug 版的包嬉愧;
執(zhí)行./gradlew assembleVIVORelease
將生成 VIVO 的 release 包。
插件化原理分析
- 插件化是指將 APK 分為宿主和插件的部分喉前。把需要實(shí)現(xiàn)的模塊或功能當(dāng)做一個(gè)獨(dú)立的提取出來(lái)没酣,在 APP 運(yùn)行時(shí)揽惹,我們可以動(dòng)態(tài)的載入或者替換插件部分,減少宿主的規(guī)模
宿主: 就是當(dāng)前運(yùn)行的 APP四康。
插件: 相對(duì)于插件化技術(shù)來(lái)說(shuō),就是要加載運(yùn)行的apk 類(lèi)文件狭握。
-
而熱修復(fù)則是從修復(fù) bug 的角度出發(fā)闪金,強(qiáng)調(diào)的是在不需要二次安裝應(yīng)用的前提下修復(fù)已知的 bug。
類(lèi)加載機(jī)制
Android 中常用的兩種類(lèi)加載器论颅,DexClassLoader 和 PathClassLoader哎垦,它們都繼承于 BaseDexClassLoader,兩者區(qū)別在于PathClassLoader 只能加載內(nèi)部存儲(chǔ)目錄的 dex/jar/apk 文件恃疯。DexClassLoader 支持加載指定目錄(不限于內(nèi)部)的 dex/jar/apk 文件插件通信:通過(guò)給插件 apk 生成相應(yīng)的 DexClassLoader 便可以訪問(wèn)其中的類(lèi)漏设,可分為單 DexClassLoader 和多 DexClassLoader 兩種結(jié)構(gòu)。
- 若使用多 ClassLoader 機(jī)制今妄,主工程引用插件中類(lèi)需要先通過(guò)插件的 ClassLoader 加載該類(lèi)再通過(guò)反 射調(diào)用其方法郑口。插件化框架一般會(huì)通過(guò)統(tǒng)一的入口去管理對(duì)各個(gè)插件中類(lèi)的訪問(wèn),并且做一定的限制盾鳞。
- 若使用單 ClassLoader 機(jī)制犬性,主工程則可以直接通過(guò)類(lèi)名去訪問(wèn)插件中的類(lèi)。該方式有個(gè)弊端腾仅,若兩個(gè)不同的插件工程引用了一個(gè)庫(kù)的不同版本乒裆,則程序可能會(huì)出錯(cuò)。
- 資源加載
原理在于通過(guò)反射將插件 apk 的路徑加入 AssetManager 中并創(chuàng)建 Resource 對(duì)象加載資源推励,有兩種處理方式:
- 合并式:addAssetPath 時(shí)加入所有插件和主工程的路徑鹤耍;由于 AssetManager 中加入了所有插件和主工程的路徑,因此生成的 Resource 可以同時(shí)訪問(wèn)插件和主工程的資源验辞。但是由于主工程和各個(gè)插件都是獨(dú)立編譯的稿黄,生成的資源 id 會(huì)存在相同的情況,在訪問(wèn)時(shí)會(huì)產(chǎn)生資源沖突跌造。
- 獨(dú)立式:各個(gè)插件只添加自己 apk 路徑抛猖,各個(gè)插件的資源是互相隔離的,不過(guò)如果想要實(shí)現(xiàn)資源的共享鼻听,必須拿到對(duì)應(yīng)的 Resource 對(duì)象财著。
組件化原理
- 引入組件化的原因:項(xiàng)目隨著需求的增加規(guī)模變得越來(lái)越大,規(guī)模的增大導(dǎo)致了各種業(yè)務(wù)錯(cuò)中復(fù)雜的交織在一起撑碴,每個(gè)業(yè)務(wù)模塊之間撑教,代碼沒(méi)有約束,帶來(lái)了代碼邊界的模糊醉拓,代碼沖突時(shí)有發(fā)生, 更改一個(gè)小問(wèn)題可能引起一些新的問(wèn)題, 牽一發(fā)而動(dòng)全身伟姐,增加一個(gè)新需求收苏,需要熟悉相關(guān)的代碼邏輯,增加開(kāi)發(fā)時(shí)間
- 避免重復(fù)造輪子愤兵,可以節(jié)省開(kāi)發(fā)和維護(hù)的成本鹿霸。
- 可以通過(guò)組件和模塊為業(yè)務(wù)基準(zhǔn)合理地安排人力,提高開(kāi)發(fā)效率秆乳。
- 不同的項(xiàng)目可以共用一個(gè)組件或模塊懦鼠,確保整體技術(shù)方案的統(tǒng)一性。
- 為未來(lái)插件化共用同一套底層模型做準(zhǔn)備屹堰。
組件化開(kāi)發(fā)流程就是把一個(gè)功能完整的 App 或模塊拆分成多個(gè)子模塊(Module)肛冶,每個(gè)子模塊可以獨(dú)立編譯運(yùn)行,也可以任意組合成另一個(gè)新的 App 或模塊扯键,每個(gè)模塊即不相互依賴但又可以相互交互睦袖,但是最終發(fā)布的時(shí)候是將這些組件合并統(tǒng)一成一個(gè) apk,遇到某些特殊情況甚至可以升級(jí)或者降級(jí)
-
舉個(gè)簡(jiǎn)單的模型例子
App 是主 application荣刑,ModuleA 和 ModuleB 是兩個(gè)業(yè)務(wù)模塊(相對(duì)獨(dú)立馅笙,互不影響),Library 是基礎(chǔ)模塊厉亏,包含所有模塊需要的依賴庫(kù)延蟹,以及一些工具類(lèi):如網(wǎng)絡(luò)訪問(wèn)、時(shí)間工具等
- 注意:提供給各業(yè)務(wù)模塊的基礎(chǔ)組件叶堆,需要根據(jù)具體情況拆分成 aar 或者 library阱飘,像登錄,基礎(chǔ)網(wǎng)絡(luò)層這樣較為穩(wěn)定的組件虱颗,一般直接打包成 aar沥匈,減少編譯耗時(shí)。而像自定義 View 組件忘渔,由于隨著版本迭代會(huì)有較多變化高帖,就直接以源碼形式抽離成 Library
跨組件通信
- 跨組件通信場(chǎng)景:
- 第一種是組件之間的頁(yè)面跳轉(zhuǎn) (Activity 到 Activity, Fragment 到 Fragment, Activity 到 Fragment, Fragment 到 Activity) 以及跳轉(zhuǎn)時(shí)的數(shù)據(jù)傳遞 (基礎(chǔ)數(shù)據(jù)類(lèi)型和可序列化的自定義類(lèi)類(lèi)型)。
- 第二種是組件之間的自定義類(lèi)和自定義方法的調(diào)用(組件向外提供服務(wù))畦粮。
- 跨組件通信方案分析:
- 第一種組件之間的頁(yè)面跳轉(zhuǎn)實(shí)現(xiàn)簡(jiǎn)單散址,跳轉(zhuǎn)時(shí)想傳遞不同類(lèi)型的數(shù)據(jù)提供有相應(yīng)的 API 即可。
- 第二種組件之間的自定義類(lèi)和自定義方法的調(diào)用要稍微復(fù)雜點(diǎn)宣赔,需要 ARouter 配合架構(gòu)中的 公共服務(wù)(CommonService) 實(shí)現(xiàn):
1)提供服務(wù)的業(yè)務(wù)模塊:
2)在公共服務(wù)(CommonService) 中聲明 Service 接口 (含有需要被調(diào)用的自定義方法), 然后在自己的模塊中實(shí)現(xiàn)這個(gè) Service 接口, 再通過(guò) ARouter API 暴露實(shí)現(xiàn)類(lèi)预麸。
3)使用服務(wù)的業(yè)務(wù)模塊:通過(guò) ARouter 的 API 拿到這個(gè) Service 接口(多態(tài)持有, 實(shí)際持有實(shí)現(xiàn)類(lèi)), 即可調(diào)用 Service 接口中聲明的自定義方法, 這樣就可以達(dá)到模塊之間的交互。
4)此外儒将,可以使用 AndroidEventBus 其獨(dú)有的 Tag, 可以在開(kāi)發(fā)時(shí)更容易定位發(fā)送事件和接受事件的代碼, 如果以組件名來(lái)作為 Tag 的前綴進(jìn)行分組, 也可以更好的統(tǒng)一管理和查看每個(gè)組件的事件, 當(dāng)然也不建議大家過(guò)多使用 EventBus吏祸。
- 如何管理過(guò)多的路由表?
RouterHub 存在于基礎(chǔ)庫(kù), 可以被看作是所有組件都需要遵守的通訊協(xié)議, 里面不僅可以放路由地址常量, 還可以放跨組件傳遞數(shù)據(jù)時(shí)命名的各種 Key 值钩蚊,再配以適當(dāng)注釋, 任何組件開(kāi)發(fā)人員不需要事先溝通只要依賴了這個(gè)協(xié)議, 就知道了各自該怎樣協(xié)同工作, 既提高了效率又降低了出錯(cuò)風(fēng)險(xiǎn), 約定的東西自然要比口頭上說(shuō)強(qiáng)贡翘。
Tips: 如果您覺(jué)得把每個(gè)路由地址都寫(xiě)在基礎(chǔ)庫(kù)的 RouterHub 中, 太麻煩了, 也可以在每個(gè)組件內(nèi)部建立一個(gè)私有 RouterHub, 將不需要跨組件的路由地址放入私有 RouterHub 中管理, 只將需要跨組件的路由地址放入基礎(chǔ)庫(kù)的公有 RouterHub 中管理, 如果您不需要集中管理所有路由地址的話, 這也是比較推薦的一種方式蹈矮。
- ARouter 路由原理:
ARouter 維護(hù)了一個(gè)路由表 Warehouse,其中保存著全部的模塊跳轉(zhuǎn)關(guān)系鸣驱,ARouter 路由跳轉(zhuǎn)實(shí)際上還是調(diào)用了 startActivity 的跳轉(zhuǎn)泛鸟,使用了原生的 Framework 機(jī)制,只是通過(guò) apt 注解的形式制造出跳轉(zhuǎn)規(guī)則踊东,并人為地?cái)r截跳轉(zhuǎn)和設(shè)置跳轉(zhuǎn)條件北滥。
Hook 以及插樁技術(shù)
-
Hook 是一種用于改變 API 執(zhí)行結(jié)果的技術(shù),能夠?qū)⑾到y(tǒng)的 API 函數(shù)執(zhí)行重定向(應(yīng)用的觸發(fā)事件和后臺(tái)邏輯處理是根據(jù)事件流程一步步地向下執(zhí)行递胧。而 Hook 的意思,就是在事件傳送到終點(diǎn)前截獲并監(jiān)控事件的傳輸赡茸,像個(gè)鉤子鉤上事件一樣缎脾,并且能夠在鉤上事件時(shí),處理一些自己特定的事件占卧,例如逆向破解 App)
- Android 中的 Hook 機(jī)制遗菠,大致有兩個(gè)方式:
- 要 root 權(quán)限,直接 Hook 系統(tǒng)华蜒,可以干掉所有的 App辙纬。
- 無(wú) root 權(quán)限,但是只能 Hook 自身 app叭喜,對(duì)系統(tǒng)其它 App 無(wú)能為力贺拣。
- 插樁是以靜態(tài)的方式修改第三方的代碼,也就是從編譯階段捂蕴,對(duì)源代碼(中間代碼)進(jìn)行編譯譬涡,而后重新打包,是靜態(tài)的篡改啥辨; 而 Hook 則不需要再編譯階段修改第三方的源碼或中間代碼涡匀,是在運(yùn)行時(shí)通過(guò)反射的方式修改調(diào)用,是一種動(dòng)態(tài)的篡改溉知。
Android 的簽名機(jī)制
Android 的簽名機(jī)制包含有消息摘要陨瘩、數(shù)字簽名和數(shù)字證書(shū):
- 消息摘要:在消息數(shù)據(jù)上,執(zhí)行一個(gè)單向的 Hash 函數(shù)级乍,生成一個(gè)固定長(zhǎng)度的Hash 值
- 數(shù)字簽名:一種以電子形式存儲(chǔ)消息簽名的方法舌劳,一個(gè)完整的數(shù)字簽名方案應(yīng)該由兩部分組成:簽名算法和驗(yàn)證算法
- 數(shù)字證書(shū):一個(gè)經(jīng)證書(shū)授權(quán)(Certificate Authentication)中心數(shù)字簽名的包含公鑰擁有者信息以及公鑰的文件
Android5.0~10.0 之間大的變化
- Android5.0 新特性
- MaterialDesign 設(shè)計(jì)風(fēng)格
- 支持 64 位 ART 虛擬機(jī)(5.0 推出的 ART 虛擬機(jī),在 5.0 之前都是 Dalvik玫荣。他們的區(qū)別是:Dalvik蒿囤,每次運(yùn)行,字節(jié)碼都需要通過(guò)即時(shí)編譯器轉(zhuǎn)換成機(jī)器碼(JIT)。 ART,第一次安裝應(yīng)用的時(shí)候,字節(jié)碼就會(huì)預(yù)先編譯成機(jī)器碼(AOT))
- 通知詳情可以用戶自己設(shè)計(jì)
- Android6.0 新特性
- 動(dòng)態(tài)權(quán)限管理
- 支持快速充電的切換
- 支持文件夾拖拽應(yīng)用
- 相機(jī)新增專(zhuān)業(yè)模式
- Android7.0 新特性
- 多窗口支持
- V2 簽名
- 增強(qiáng)的 Java8 語(yǔ)言模式
- 夜間模式
- Android8.0 新特性
- 優(yōu)化通知:通知渠道 (Notification Channel) 通知標(biāo)志 休眠 通知超時(shí) 通知設(shè)置 通知清除
- 畫(huà)中畫(huà)模式:清單中 Activity 設(shè)置 android:supportsPictureInPicture
- 后臺(tái)限制
- 自動(dòng)填充框架
- 系統(tǒng)優(yōu)化
- 等等優(yōu)化很多
- Android9.0(P)新特性
- 室內(nèi) WIFI 定位
- “劉撼缇觯”屏幕支持
- 安全增強(qiáng)
- 等等優(yōu)化很多
- Android10.0(Q)目前曝光的新特性
- 夜間模式:包括手機(jī)上的所有應(yīng)用都可以為其設(shè)置暗黑模式材诽。
- 桌面模式:提供類(lèi)似于 PC 的體驗(yàn)底挫,但是遠(yuǎn)遠(yuǎn)不能代替 PC。
- 屏幕錄制:通過(guò)長(zhǎng)按“電源”菜單中的"屏幕快照"來(lái)開(kāi)啟脸侥。
使用過(guò)什么圖片加載庫(kù)建邓?Glide 的源碼設(shè)計(jì)哪里很微妙?
- 圖片加載庫(kù):Fresco睁枕、Glide官边、Picasso 等
- Glide 的設(shè)計(jì)微妙在于:
- Glide 的生命周期綁定:可以控制圖片的加載狀態(tài)與當(dāng)前頁(yè)面的生命周期同步,使整個(gè)加載過(guò)程隨著頁(yè)面的狀態(tài)而啟動(dòng)/恢復(fù)外遇,停止注簿,銷(xiāo)毀
- Glide 的緩存設(shè)計(jì):通過(guò)(三級(jí)緩存,Lru 算法跳仿,Bitmap 復(fù)用)對(duì) Resource 進(jìn)行緩存設(shè)計(jì)
- Glide 的完整加載過(guò)程:采用 Engine 引擎類(lèi)暴露了一系列方法供 Request 操作
對(duì)于應(yīng)用更新這塊是如何做的诡渴? (灰度,強(qiáng)制更新菲语、分區(qū)域更新)
- 內(nèi)部更新:
- 通過(guò)接口獲取線上版本號(hào)妄辩,versionCode
- 比較線上的 versionCode 和本地的 versionCode,彈出更新窗口
- 下載 APK 文件(文件下載)
- 安裝 APK
- 灰度更新:
- 找單一渠道投放特別版本山上。
- 做升級(jí)平臺(tái)的改造眼耀,允許針對(duì)部分用戶推送升級(jí)通知甚至版本強(qiáng)制升級(jí)。
- 開(kāi)放單獨(dú)的下載入口佩憾。
- 是兩個(gè)版本的代碼都打到 app 包里哮伟,然后在 app 端植入測(cè)試框架,用來(lái)控制顯示哪個(gè)版本妄帘。測(cè)試框架負(fù)責(zé)與服務(wù)器端 api 通信澈吨,由服務(wù)器端控制 app 上A/B 版本的分布,可以實(shí)現(xiàn)指定的一組用戶看到 A版本寄摆,其它用戶看到 B 版本谅辣。服務(wù)端會(huì)有相應(yīng)的報(bào)表來(lái)顯示 A/B 版本的數(shù)量和效果對(duì)比。最后可以由服務(wù)端的后臺(tái)來(lái)控制婶恼,全部用戶在線切換到 A 或者 B 版本~
- 無(wú)論哪種方法都需要做好版本管理工作桑阶,分配特別的版本號(hào)以示區(qū)別。 當(dāng)然勾邦,既然是做灰度蚣录,數(shù)據(jù)監(jiān)控(常規(guī)數(shù)據(jù)、新特性數(shù)據(jù)眷篇、主要業(yè)務(wù)數(shù)據(jù))還是要做到位萎河,該打的數(shù)據(jù)樁要打。 還有,灰度版最好有收回的能力虐杯,一般就是強(qiáng)制升級(jí)下一個(gè)正式版玛歌。
強(qiáng)制更新:
一般的處理就是進(jìn)入應(yīng)用就彈窗通知用戶有版本更新,彈窗可以沒(méi)有取消按鈕并不能取消擎椰。這樣用戶就只能選擇更新或者關(guān)閉應(yīng)用了支子,當(dāng)然也可以添加取消按鈕,但是如果用戶選擇取消則直接退出應(yīng)用达舒。增量更新:
二進(jìn)制差分工具 bsdiff 是相應(yīng)的補(bǔ)丁合成工具值朋,根據(jù)兩個(gè)不同版本的二進(jìn)制文件,生成補(bǔ)丁文件.patch 文件巩搏。通過(guò) bspatch 使舊的 apk 文件與不定文件合成新的 apk昨登。 注意通過(guò) apk 文件的 md5 值進(jìn)行區(qū)分版本。
會(huì)用 Kotlin贯底、Fultter 嗎丰辣? 談?wù)勀愕睦斫?/h1>
- Kotlin 是一種具有類(lèi)型推斷的跨平臺(tái),靜態(tài)類(lèi)型的通用編程語(yǔ)言丈甸。 Kotlin 旨在與 Java 完全互操作糯俗,其標(biāo)準(zhǔn)庫(kù)的JVM 版本依賴于 Java 類(lèi)庫(kù)尿褪,但類(lèi)型推斷允許其語(yǔ)法更簡(jiǎn)潔睦擂。
- Flutter 是由 Google 創(chuàng)建的開(kāi)源移動(dòng)應(yīng)用程序開(kāi)發(fā)框架。它用于開(kāi)發(fā) Android 和 iOS 的應(yīng)用程序杖玲,以及為 Google Fuchsia 創(chuàng)建應(yīng)用程序的主要方法
- 關(guān)于 kotlin 的重要性顿仇,相信大家在日常開(kāi)發(fā)可以體會(huì)到,應(yīng)用到實(shí)際開(kāi)發(fā)中摆马,需要避免語(yǔ)法糖(例如單列模式臼闻、空值判斷、高階函數(shù)等)
- 至于 Flutter囤采,目前 Google 官方文檔還不完善述呐,市面上采用此語(yǔ)言編寫(xiě)的項(xiàng)目較少,如需要具體深入蕉毯,請(qǐng)參考閑魚(yú)和官方文檔
說(shuō)一下常見(jiàn)內(nèi)存泄漏及優(yōu)化方案
內(nèi)存泄露在 Android 內(nèi)存優(yōu)化是一個(gè)比較重要的一個(gè)方面乓搬,很多時(shí)候程序中發(fā)生了內(nèi)存泄露我們 不一定就能注意到,所有在編碼的過(guò)程要養(yǎng)成良好的習(xí)慣代虾〗希總結(jié)下來(lái)只要做到以下這幾點(diǎn)就能避 免大多數(shù)情況的內(nèi)存泄漏:
- 構(gòu)造單例的時(shí)候盡量別用 Activity 的引用;
- 靜態(tài)引用時(shí)注意應(yīng)用對(duì)象的置空或者少用靜態(tài)引用;
- 使用靜態(tài)內(nèi)部類(lèi)+軟引用代替非靜態(tài)內(nèi)部類(lèi);
- 及時(shí)取消廣播或者觀察者注冊(cè);
- 耗時(shí)任務(wù)、屬性動(dòng)畫(huà)在 Activity 銷(xiāo)毀時(shí)記得 cancel;
- 文件流棉磨、Cursor 等資源及時(shí)關(guān)閉;
- Activity 銷(xiāo)毀時(shí) WebView 的移除和銷(xiāo)毀江掩。