Android性能優(yōu)化之APP性能優(yōu)化原則總結(jié)

??使用過(guò)Android系統(tǒng)手機(jī)的同學(xué)都知道,Android手機(jī)越用越卡,這個(gè)卡主要體現(xiàn)在手機(jī)系統(tǒng)越用越卡,打開(kāi)APP的速度越來(lái)越慢丘逸。Android手機(jī)越用越卡的原因主要有:1挽放、Android系統(tǒng)源碼是開(kāi)放的绍赛,像國(guó)內(nèi)的幾大手機(jī)廠商,都是對(duì)系統(tǒng)進(jìn)入定制開(kāi)發(fā)辑畦,這樣就會(huì)引發(fā)一系列問(wèn)題吗蚌,比如說(shuō)著名的系統(tǒng)碎片化問(wèn)題;2纯出、APP開(kāi)發(fā)人員要對(duì)各個(gè)系統(tǒng)做各種適配蚯妇,開(kāi)發(fā)人員的水平參次不齊,開(kāi)發(fā)出來(lái)的APP就會(huì)出現(xiàn)這樣那樣的問(wèn)題暂筝。

??Android應(yīng)用的性能優(yōu)化是每個(gè)Android開(kāi)發(fā)人員必然會(huì)遇到的箩言,也是跳槽面試時(shí)基本必問(wèn)的問(wèn)題。下面是筆者總結(jié)的一些APP性能優(yōu)化原則焕襟,如果能遵循下面這些優(yōu)化原則陨收,那么開(kāi)發(fā)出來(lái)的APP肯定會(huì)更流暢一點(diǎn)、用戶體驗(yàn)更好一點(diǎn)鸵赖、更穩(wěn)定一點(diǎn)务漩。

1.布局優(yōu)化

??思想概述: 盡量減少布局文件的層次(android繪制時(shí)的工作量減小,性能提高)它褪,避免過(guò)渡繪制饵骨。
??首先刪除布局中無(wú)用的控件和層級(jí),其次有選擇地使用性能較低的ViewGroup茫打,比如LinearLayout居触。如果布局中有的布局既可以用LinearLayout也可以用RelativeLayout,那就用LinearLayout老赤,這是因?yàn)镽elativeLayout比較復(fù)雜轮洋,他的布局過(guò)程花費(fèi)更多的CPU時(shí)間。FrameLayout和LinearLayout一樣都是一種簡(jiǎn)單高效的ViewGroup抬旺,因此可以考慮使用他們弊予,但是很多時(shí)候,單純的通過(guò)一個(gè)LinearLayout或者FrameLayout無(wú)法實(shí)現(xiàn)產(chǎn)品的效果嚷狞,需要通過(guò)嵌套的方式來(lái)完成块促,這種情況建議采用RelativeLayout荣堰,因?yàn)閂iewGroup的嵌套就相當(dāng)于增加了布局的層級(jí)床未,同樣會(huì)降低程序的性能。
??布局優(yōu)化的另一種手段是采用<merge>標(biāo)簽振坚、<include>標(biāo)簽和ViewStub:

  1. <merge>標(biāo)簽:如果當(dāng)前布局和包含的布局中都是豎直方向薇搁,那么使用<merge>標(biāo)簽可以去掉多余的LinearLayout,一般和<include>標(biāo)簽一起使用渡八,從而減少布局的層級(jí)啃洋;
  2. <include>標(biāo)簽:布局重用传货,不用把已經(jīng)寫過(guò)的布局重新寫一遍,代碼的復(fù)用宏娄;
  3. ViewStub:繼承view问裕,非常輕量級(jí)且寬高都是0,自己不參加任何布局的繪制過(guò)程孵坚,提供了按需加載功能粮宛,當(dāng)需要時(shí)才將ViewStub中的布局加載到內(nèi)存,這提高了程序的初始化效率卖宠。

2.繪制優(yōu)化

??思想概述:View的onDraw方法避免大量的操作巍杈,onDraw方法中不要?jiǎng)?chuàng)建新的局部對(duì)象(onDraw方法可能被頻繁調(diào)用,會(huì)產(chǎn)生大量的臨時(shí)對(duì)象扛伍,導(dǎo)致系統(tǒng)更加頻繁的gc筷畦,降低程序的執(zhí)行效率),onDraw方法中不要做耗時(shí)的任務(wù)刺洒,不能執(zhí)行成千上萬(wàn)次的循環(huán)操作(搶占cpu的時(shí)間片鳖宾,造成View繪制過(guò)程不夠流暢,每幀的繪制時(shí)間不超過(guò)16ms)作媚。

3.內(nèi)存泄露優(yōu)化

??內(nèi)存泄露的優(yōu)化的思路主要分為兩個(gè)方面:一方面是在開(kāi)發(fā)過(guò)程中避免寫出內(nèi)存泄露的代碼攘滩,另一方面通過(guò)一些分析工具比如MAT、LeakCanry或Android Profiler等來(lái)找出潛在的內(nèi)存泄露繼而解決纸泡。
??常見(jiàn)的內(nèi)存泄露舉例:

  1. Context使用不當(dāng)造成內(nèi)存泄露:不要對(duì)一個(gè)Activity漂问、 Context保持長(zhǎng)生命周期的引用,盡量在一切可以使用應(yīng)用ApplicationContext代替Context的地方進(jìn)行替換)女揭;
  2. 靜態(tài)變量導(dǎo)致內(nèi)存泄露:如果我們將activity的context對(duì)象賦值給activity的全局的靜態(tài)變量蚤假。那么就會(huì)造成activity無(wú)法正常銷毀,因?yàn)殪o態(tài)變量在引用它吧兔;
  3. 單例模式導(dǎo)致的內(nèi)存泄漏:如果我們?cè)趩卫J街袑?shí)現(xiàn)了觀察者模式磷仰,監(jiān)聽(tīng)實(shí)現(xiàn)了接口的對(duì)象,當(dāng)我們?cè)贏ctivity中注冊(cè)了監(jiān)聽(tīng)方法以后境蔼,而沒(méi)有進(jìn)行解注冊(cè),就會(huì)引起內(nèi)存泄漏灶平;在單例模式初始化是,如果傳入Activity或Context實(shí)例箍土,也會(huì)引起內(nèi)存泄露逢享;
  4. 屬性動(dòng)畫(huà)導(dǎo)致的內(nèi)存泄露:屬性動(dòng)畫(huà)中有一類無(wú)限循環(huán)的動(dòng)畫(huà),如果在Activity中播放此類動(dòng)畫(huà)而沒(méi)有在onDestory中停止動(dòng)畫(huà)吴藻,那么動(dòng)畫(huà)會(huì)一直播放下去瞒爬,盡管無(wú)法在界面上看到動(dòng)畫(huà)效果了,而且這個(gè)時(shí)候,Activity的View會(huì)被動(dòng)畫(huà)持有侧但,而View有持有了Activity矢空,最終導(dǎo)致Activity無(wú)法釋放;
  5. 警惕線程未終止造成的內(nèi)存泄露:譬如在Activity中關(guān)聯(lián)了一個(gè)生命周期超過(guò)Activity的Thread禀横,在退出Activity時(shí)切記要結(jié)束線程屁药。一個(gè)典型的例子就是HandlerThread的run方法是一個(gè)死循環(huán),它不會(huì)自己結(jié)束柏锄,線程的生命周期超過(guò)了Activity生命周期者祖,我們必須手動(dòng)在Activity的銷毀方法中調(diào)用handlerThread.quit()才不會(huì)泄露;
  6. 對(duì)象的注冊(cè)與反注冊(cè)沒(méi)有成對(duì)出現(xiàn)造成的內(nèi)存泄露绢彤;譬如注冊(cè)廣播接收器七问、注冊(cè)觀察者(典型的譬如數(shù)據(jù)庫(kù)的監(jiān)聽(tīng))等;
  7. 創(chuàng)建與關(guān)閉沒(méi)有成對(duì)出現(xiàn)造成的泄露茫舶;如Cursor資源必須手動(dòng)關(guān)閉械巡,WebView必須手動(dòng)銷毀,流等對(duì)象必須手動(dòng)關(guān)閉等饶氏;
  8. 非靜態(tài)內(nèi)部類的靜態(tài)實(shí)例容易造成內(nèi)存泄漏讥耗;即一個(gè)類中如果你不能夠控制它其中內(nèi)部類的生命周期(譬如Activity中的一些特殊Handler等),則盡量使用靜態(tài)類和弱引用來(lái)處理(譬如ViewRoot的實(shí)現(xiàn))疹启;
  9. 不要在執(zhí)行頻率很高的方法或者循環(huán)中創(chuàng)建對(duì)象古程,可以使用HashTable等創(chuàng)建一組對(duì)象容器從容器中取那些對(duì)象,而不用每次new與釋放喊崖;
  10. 注意WebView的泄漏:Android中的WebView存在很大的兼容性問(wèn)題挣磨,解決方法是:讓onDetachedFromWindow先走,在主動(dòng)調(diào)用destroy()之前荤懂,把webview從它的parent上面移除掉茁裙,具體代碼如下:
@Override
protected void onDestroy() {
    if( mWebView!=null) {
        // 如果先調(diào)用destroy()方法,則會(huì)命中if (isDestroyed()) return;這一行代碼节仿,需要先onDetachedFromWindow()晤锥,再
        // destory()
        ViewParent parent = mWebView.getParent();
        if (parent != null) {
            ((ViewGroup) parent).removeView(mWebView);
        }

        mWebView.stopLoading();
        // 退出時(shí)調(diào)用此方法,移除綁定的服務(wù)廊宪,否則某些特定系統(tǒng)會(huì)報(bào)錯(cuò)
        mWebView.getSettings().setJavaScriptEnabled(false);
        mWebView.clearHistory();
        mWebView.clearView();
        mWebView.removeAllViews();
        mWebView.destroy();

    }
    super.on Destroy();
}

PS:內(nèi)存泄露和內(nèi)存溢出OOM的關(guān)系:內(nèi)存泄露小范圍積累不能釋放會(huì)導(dǎo)致卡頓矾瘾,內(nèi)存泄露長(zhǎng)期不能釋放,累積超過(guò)閾值會(huì)引起OOM箭启,如果瞬間申請(qǐng)的內(nèi)存超過(guò)應(yīng)用允許的閾值也會(huì)引起OOM(如應(yīng)用的某些邏輯操作瘋狂的消耗掉大量?jī)?nèi)存(譬如加載一張不經(jīng)過(guò)處理的超大超高清圖片等)導(dǎo)致超過(guò)閾值引起OOM)壕翩,可見(jiàn)兩者是交集關(guān)系。內(nèi)存溢出(OutOfMemoryError)的核心原因就是應(yīng)用的內(nèi)存超過(guò)閾值了册烈。

4.響應(yīng)速度優(yōu)化

??響應(yīng)速度優(yōu)化的核心是避免在主線程中做耗時(shí)操作戈泼,而是將這些耗時(shí)操作放在子線程中去執(zhí)行,即采用異步的方式去執(zhí)行赏僧。響應(yīng)速度過(guò)慢體現(xiàn)在Activity的啟動(dòng)畫(huà)面上大猛,如果在主線程中做太多的事情,會(huì)導(dǎo)致Activity啟動(dòng)時(shí)出現(xiàn)黑屏的現(xiàn)象淀零,甚至出現(xiàn)ANR挽绩。當(dāng)發(fā)生了ANR以后。系統(tǒng)會(huì)在/data/anr目錄創(chuàng)建一個(gè)文件traces.txt(PS:不同的手機(jī)存儲(chǔ)的路徑可能會(huì)有不同)驾中,通過(guò)分析trace文件唉堪,可以進(jìn)一步定位ANR的原因。

5.ListView的優(yōu)化

??ListView的優(yōu)化很簡(jiǎn)單肩民,其思想概述:首先采用ViewHolder并避免在getView中執(zhí)行耗時(shí)操作唠亚;其次要根據(jù)列表的滑動(dòng)狀態(tài)來(lái)控制任務(wù)的執(zhí)行頻率,比如當(dāng)列表快速滑動(dòng)時(shí)顯然是不太適合開(kāi)啟大量的異步任務(wù)持痰;最后灶搜,可以嘗試開(kāi)啟硬件加速來(lái)使ListView的滑動(dòng)更加流暢。

??ListView的優(yōu)化現(xiàn)在最流行的方式是用RecyclerView代替工窍,若用RecyclerView代替ListView顯示列表數(shù)據(jù)割卖,可以忽略該原則。

6.Bitmap優(yōu)化

??Bitmap優(yōu)化同樣比較簡(jiǎn)單患雏,其思想概述:1鹏溯、通過(guò)BitMapFactory.Options來(lái)根據(jù)需要對(duì)圖片進(jìn)行采樣,采樣過(guò)程主要用到了BitmapFactory.Options的inSampleSize參數(shù)淹仑;2丙挽、利用inBitmap的高級(jí)特性提高Android系統(tǒng)在Bitmap分配與釋放執(zhí)行效率上的提升,使用該變量可以復(fù)用舊的Bitmap的內(nèi)存而不用重新分配以及銷毀舊Bitmap匀借,進(jìn)而改善運(yùn)行效率取试,即復(fù)用了內(nèi)存減少了內(nèi)存占用(只要新的Bitmap的內(nèi)存小于舊Bitmap的內(nèi)存大小,即可進(jìn)行復(fù)用的操作怀吻;Glide內(nèi)部也使用了inBitmap作為緩存復(fù)用的一種方式瞬浓。)。

7.線程優(yōu)化

??思想概述:采用線程池蓬坡,避免程序中存在大量的Thread猿棉。線程池可以重用內(nèi)部的線程,從而避免了線程的創(chuàng)建和銷毀所帶來(lái)的性能開(kāi)銷屑咳。同時(shí)線程池還能有效的控制線程池的最大并發(fā)數(shù)萨赁,避免大量的線程互相搶占系統(tǒng)資源從而導(dǎo)致阻塞現(xiàn)象發(fā)生。

8.其他性能優(yōu)化原則

  1. 避免創(chuàng)建過(guò)多的對(duì)象兆龙;
  2. 不要過(guò)多的使用枚舉杖爽,因?yàn)槊杜e占用的內(nèi)存空間要比標(biāo)準(zhǔn)類型大敲董;
  3. 常量使用static final修飾;
  4. 采用內(nèi)存緩存和磁盤緩存慰安;
  5. 使用更小的圖片:盡量使用更小的圖片資源腋寨;
  6. 采用靜態(tài)內(nèi)部類,這樣可以避免潛在的由于內(nèi)部類而導(dǎo)致的內(nèi)存泄漏化焕;
  7. 用好Lint工具:AndroidStudio自帶的Lint工具可以檢查出APP代碼里面潛在的更多的優(yōu)化建議萄窜;
  8. 使用ProGuard來(lái)剔除不需要的代碼:ProGuard能夠通過(guò)移除不需要的代碼,重命名類撒桨,域與方法等等對(duì)代碼進(jìn)行壓縮查刻,優(yōu)化與混淆。使用ProGuard可以使得你的代碼更加緊湊凤类,這樣能夠減少mapping代碼所需要的內(nèi)存空間穗泵。

??如果感覺(jué)我的文章對(duì)您有所幫助,麻煩動(dòng)動(dòng)小手給個(gè)喜歡谜疤,如果有疑問(wèn)火欧,也歡迎在下方留言,謝謝>ソ亍N帧!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末企锌,一起剝皮案震驚了整個(gè)濱河市榆浓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撕攒,老刑警劉巖陡鹃,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異抖坪,居然都是意外死亡萍鲸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門擦俐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)脊阴,“玉大人,你說(shuō)我怎么就攤上這事蚯瞧『倨冢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵埋合,是天一觀的道長(zhǎng)备徐。 經(jīng)常有香客問(wèn)我,道長(zhǎng)甚颂,這世上最難降的妖魔是什么蜜猾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任秀菱,我火速辦了婚禮,結(jié)果婚禮上蹭睡,老公的妹妹穿的比我還像新娘衍菱。我一直安慰自己,他們只是感情好棠笑,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著禽绪,像睡著了一般蓖救。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上印屁,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天循捺,我揣著相機(jī)與錄音,去河邊找鬼雄人。 笑死从橘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的础钠。 我是一名探鬼主播恰力,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼旗吁!你這毒婦竟也來(lái)了踩萎?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤很钓,失蹤者是張志新(化名)和其女友劉穎香府,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體码倦,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡企孩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袁稽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勿璃。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖推汽,靈堂內(nèi)的尸體忽然破棺而出蝗柔,到底是詐尸還是另有隱情,我是刑警寧澤民泵,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布癣丧,位于F島的核電站,受9級(jí)特大地震影響栈妆,放射性物質(zhì)發(fā)生泄漏胁编。R本人自食惡果不足惜厢钧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嬉橙。 院中可真熱鬧早直,春花似錦、人聲如沸市框。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)枫振。三九已至喻圃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粪滤,已是汗流浹背斧拍。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杖小,地道東北人肆汹。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像予权,于是被迫代替她去往敵國(guó)和親昂勉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349