這些坑主要分為幾個(gè)類(lèi):分為系統(tǒng)API的坑、使用不當(dāng)導(dǎo)致的坑、開(kāi)源項(xiàng)目中的坑等幾個(gè)方面
1.系統(tǒng)API的坑##
(1) Android library中的資源ID在R.java中不是final類(lèi)型:
??問(wèn)題現(xiàn)象:在library中使用switch語(yǔ)句區(qū)分不同的資源ID時(shí)揽思,IDE會(huì)報(bào)錯(cuò)宰闰;
??原因分析:這個(gè)問(wèn)題在Android Studio Project Site (http://tools.android.com/tips/non-constant-fields)有提及,在ADT14及以上的版本中郊霎,library所對(duì)應(yīng)的R.java中所有ID不再是final類(lèi)型沼头,所以不能將ID作為switch語(yǔ)句中的case分支屬性值。這個(gè)問(wèn)題和IDE無(wú)關(guān)书劝,在Eclipse和AS中都存在进倍。
??解決方案:如果涉及到區(qū)分多個(gè)ID的情況(比如監(jiān)聽(tīng)回調(diào)事件、初始化通過(guò)xml給自定義View設(shè)置的屬性值等)應(yīng)該使用if...else if...else代替switch語(yǔ)句购对;
(2) 同一個(gè)程序內(nèi)的多個(gè)進(jìn)程之間使用SharedPreferences不安全:
??問(wèn)題現(xiàn)象:在同一個(gè)程序內(nèi)使用多進(jìn)程時(shí)猾昆,在不同進(jìn)程間使用SharedPreferences操作數(shù)據(jù)會(huì)導(dǎo)致SF中的數(shù)據(jù)隨機(jī)丟失的情況(獲取到的值為空);
??原因分析:雖然API中提供了Context.MODEMULTIPROCESS模式打開(kāi)SF文件骡苞,但在官方文檔(https://developer.android.com/reference/android/content/SharedPreferences.html)中已有說(shuō)明:“currently this class does not support use across multiple processes”垂蜗,因?yàn)镾F在多進(jìn)程間操作是不安全的,并行操作時(shí)會(huì)導(dǎo)致寫(xiě)沖突解幽。
??解決方案:Github上有個(gè)開(kāi)源項(xiàng)目Tray(https://github.com/grandcentrix/tray)贴见,專(zhuān)門(mén)針對(duì)在多進(jìn)程中使用SF不安全的問(wèn)題提供的解決方案。
(3) Typeface初始化自定義字體慢:
??問(wèn)題現(xiàn)象:在使用自定義字體的頁(yè)面亚铁,進(jìn)入慢蝇刀;
??原因分析:使用Typeface初始化字體很耗時(shí),至少需要100ms(不同文件耗時(shí)不一樣)以上的時(shí)間徘溢。
??解決方案:如果在Activity的onCreate方法中初始化Typeface吞琐,會(huì)導(dǎo)致進(jìn)入Activity慢捆探,出現(xiàn)黑屏/白屏現(xiàn)象,所以應(yīng)該盡量在非UI線程中做自定義字體的初始化操作站粟。
(4) Activity在沒(méi)有完全顯示/已退出的情況下顯示PopupWindow異常:
??問(wèn)題現(xiàn)象:進(jìn)入Activity界面直接報(bào)錯(cuò)黍图,log異常顯示為:"Unable to add window -- token null is not valid";
??原因分析:原因是在Activity的onCreate方法中直接顯示了PopupWindow導(dǎo)致奴烙,PopupWindow的顯示是依附在某一個(gè)View上面的(showAtLocation方法第一個(gè)參數(shù)為需要依附的view)助被,在Activity沒(méi)有完全顯示時(shí),PopupWindow無(wú)法依附在該View上切诀,如果在此時(shí)顯示PopupWindow會(huì)導(dǎo)致上面的異常揩环,同樣在退出Activity后也不能正常顯示PopupWindow。
??解決方案:在開(kāi)發(fā)過(guò)程中需要考慮通過(guò)異步顯示PopupWindow幅虑,避免PoupWindow顯示報(bào)異常的問(wèn)題丰滑。
(4) Activity的onDestory方法調(diào)用時(shí)機(jī)不確定:
??問(wèn)題現(xiàn)象:連續(xù)進(jìn)入、退出某一個(gè)Activity倒庵,會(huì)出現(xiàn)Activity Crash掉的現(xiàn)象褒墨;
??原因分析:在Activity的onCreate做的初始化操作(打開(kāi)文件),在onDestory做的銷(xiāo)毀操作(關(guān)閉文件)擎宝;退出Activity后onDestory并沒(méi)有立即調(diào)用郁妈,再次快速進(jìn)入該Activity時(shí),該Activity是另外一個(gè)實(shí)例绍申,并且首先調(diào)用了新Activity的onCreate方法之后再才調(diào)用上個(gè)Activity實(shí)例的onDestory方法噩咪,導(dǎo)致文件剛被打開(kāi)就關(guān)閉了,在程序使用數(shù)據(jù)時(shí)Crash掉极阅;
??解決方案:準(zhǔn)確來(lái)講只要是系統(tǒng)方法剧腻,調(diào)用時(shí)機(jī)都不確定。對(duì)于這種問(wèn)題只能盡量不要在Activity的系統(tǒng)回調(diào)方法中做資源初始化和釋放的操作涂屁,比如涉及到IO操作的情況,在使用的時(shí)候才打開(kāi)灰伟,使用完后立即關(guān)閉拆又;
(5) 透明主題導(dǎo)致Activity生命周期回調(diào)的變化:
??問(wèn)題現(xiàn)象:從當(dāng)前Activity跳轉(zhuǎn)到其它Activity時(shí),當(dāng)前Activity的onStop方法并沒(méi)有調(diào)用栏账;
??原因分析:給當(dāng)前Activity設(shè)置為透明主題導(dǎo)致帖族,通過(guò)添加打印跟蹤發(fā)現(xiàn),從該Activity跳轉(zhuǎn)到其它Activity時(shí)挡爵,該Activity的onStop方法不會(huì)執(zhí)行竖般;
??解決方案:謹(jǐn)慎使用透明主題,如果必須要為Activity設(shè)置為透明主題茶鹃,不要在onStop方法中做任何操作涣雕,因?yàn)樵摲椒ú⒉粫?huì)被調(diào)用艰亮。透明主題存在很多問(wèn)題,比如在設(shè)置為透明主題的界面按Home按鍵時(shí)挣郭,會(huì)存在界面刷不干凈的情況迄埃。
(6) 不要通過(guò)Bundle傳遞很大塊的數(shù)據(jù):
??問(wèn)題現(xiàn)象:從目錄界面跳轉(zhuǎn)到內(nèi)容顯示界面,出現(xiàn)隨機(jī)崩潰的現(xiàn)象兑障,報(bào)的異常是:TransactionTooLargeException侄非;
??原因分析:跟蹤發(fā)現(xiàn)如果通過(guò)Bundle傳遞太大塊(>1M)的數(shù)據(jù)會(huì)在程序運(yùn)行時(shí)報(bào)TransactionTooLargeException異常,具體原因可以上官網(wǎng)查看流译,大致意思是傳遞的序列化數(shù)據(jù)不能超過(guò)1M逞怨,否則會(huì)報(bào)TransactionTooLargeException異常;之所以隨機(jī)是因?yàn)槊看蝹鬟f的數(shù)據(jù)大小不一樣福澡。
??解決方案:如果你在不同組件之間傳遞的數(shù)據(jù)太大叠赦,甚至超過(guò)了1M,為了提高效率和程序的穩(wěn)定性竞漾,建議通過(guò)持久化的方式傳遞數(shù)據(jù)眯搭,即在傳遞方寫(xiě)文件,在接收方去讀取這個(gè)文件业岁;
(6) 不要在Application類(lèi)中緩存數(shù)據(jù):
??問(wèn)題現(xiàn)象:程序從后臺(tái)切換到前臺(tái)鳞仙,直接崩了;
??原因分析:程序在后臺(tái)時(shí)笔时,為了給正在運(yùn)行的程序提供更多可使用的內(nèi)存棍好,Application中的數(shù)據(jù)可能會(huì)被清理掉,如果在Application中緩存了數(shù)據(jù)允耿,并且在程序重新回到前臺(tái)時(shí)沒(méi)有做好恢復(fù)工作借笙,程序會(huì)出現(xiàn)不可預(yù)見(jiàn)的情況(比如數(shù)據(jù)錯(cuò)亂、崩潰等)较锡,具體可以參照這篇文章Don't Store Data in the Application Object业稼;
??解決方案:不要在Application中緩存數(shù)據(jù)。
(7) 使用AsyncTask無(wú)法避開(kāi)的坑:
??問(wèn)題現(xiàn)象:使用AsyncTask異步執(zhí)行的任務(wù)并沒(méi)有立即執(zhí)行蚂蕴;
??原因分析:AsyncTask這個(gè)類(lèi)的實(shí)現(xiàn)可謂一波三折低散,方案修改了好幾個(gè)版本,初次引入這個(gè)類(lèi)時(shí)骡楼,所有的Task是放在一個(gè)獨(dú)立的后臺(tái)線程中執(zhí)行的熔号,也就是如果有多個(gè)Task同時(shí)被調(diào)用也是順序執(zhí)行的;從1.6開(kāi)始鸟整,改為通過(guò)線程池可以支持并行執(zhí)行多個(gè)Task引镊;但從3.0開(kāi)始,又改回只有一個(gè)獨(dú)立的后臺(tái)線程執(zhí)行所有Task,主要是為了避免多個(gè)Task并行執(zhí)行導(dǎo)致的程序錯(cuò)誤弟头,但為了讓AsyncTask能夠支持多個(gè)Task并行執(zhí)行吩抓,從3.0起,增加了executeOnExecutor方法亮瓷,調(diào)用者自行實(shí)現(xiàn)線程池可以達(dá)到并行多個(gè)Task的效果琴拧。
??解決方案:如果在某個(gè)地方需要同時(shí)執(zhí)行多個(gè)異步任務(wù),強(qiáng)烈建議使用線程池嘱支;
(8) 數(shù)據(jù)庫(kù)升級(jí)中的坑:
??問(wèn)題現(xiàn)象:在數(shù)據(jù)庫(kù)的某個(gè)表中增加/修改了某個(gè)字段后蚓胸,程序在運(yùn)行時(shí)崩潰掉了;或者在增加字段時(shí)修改了數(shù)據(jù)庫(kù)的版本號(hào)除师,但程序升級(jí)后沛膳,原來(lái)的數(shù)據(jù)丟失了;
??原因分析:SQlite數(shù)據(jù)庫(kù)升級(jí)時(shí)需要修改OpenHelper中的版本號(hào)汛聚,并且數(shù)據(jù)庫(kù)升級(jí)會(huì)刪掉原來(lái)數(shù)據(jù)庫(kù)中的數(shù)據(jù)锹安,需要手動(dòng)將原數(shù)據(jù)庫(kù)中的數(shù)據(jù)拷貝到高版本的數(shù)據(jù)庫(kù)中;
??解決方案:做好數(shù)據(jù)庫(kù)升級(jí)的恢復(fù)工作倚舀,避免出現(xiàn)崩潰叹哭、數(shù)據(jù)丟失的情況。
(9) 程序在未啟動(dòng)的情況下痕貌,靜態(tài)注冊(cè)的廣播無(wú)法收到消息:
??問(wèn)題現(xiàn)象:程序添加了對(duì)開(kāi)機(jī)廣播的監(jiān)聽(tīng)风罩,但無(wú)法接收到;
??原因分析:這個(gè)問(wèn)題只有在程序安裝但沒(méi)有啟動(dòng)時(shí)才會(huì)出現(xiàn)舵稠,只要程序啟動(dòng)過(guò)一次后就不會(huì)有這個(gè)問(wèn)題超升。并且只有在Android 3.1及以上的版本才會(huì)出現(xiàn),具體原因是:從Android3.1開(kāi)始哺徊,新安裝的程序會(huì)被置于"stopped"狀態(tài)室琢,并且只有在至少手動(dòng)啟動(dòng)這個(gè)程序一次后該程序才會(huì)改變狀態(tài),能夠正常接收到指定的廣播消息落追。Android這樣做的目的是防止廣播無(wú)意或者不必要地開(kāi)啟未啟動(dòng)的APP后臺(tái)服務(wù)盈滴。也就是說(shuō)在Android3.1及以上的版本,程序在未啟動(dòng)的情況下通過(guò)應(yīng)用自身完成一些操作是不可能的轿钠,但Android提供了一種借助其它應(yīng)用發(fā)送指定Flag廣播的方式雹熬,達(dá)到應(yīng)用在未啟動(dòng)的情況下仍然能夠收到消息的效果。從Android 3.1開(kāi)始谣膳,系統(tǒng)給Intent定義了兩個(gè)新的Flag,分別為FLAGINCLUDESTOPPEDPACKAGES(表示包含未啟動(dòng)的App)和FLAGEXCLUDESTOPPEDPACKAGES(表示不包含未啟動(dòng)的App)铅乡,用來(lái)控制Intent是否要對(duì)處于停止?fàn)顟B(tài)的App起作用继谚。
??解決方案:只能借助其它應(yīng)用給自己發(fā)送帶FLAG_INCLUDESTOPPEDPACKAGES標(biāo)志的廣播才能實(shí)現(xiàn)在程序未啟動(dòng)的情況下接收到廣播;
(10) android:windowBackground導(dǎo)致的過(guò)渡繪制問(wèn)題:
??問(wèn)題現(xiàn)象:界面的布局已無(wú)法進(jìn)一步優(yōu)化阵幸,但仍然存在過(guò)渡繪制的問(wèn)題花履;
??原因分析:window存在默認(rèn)的背景芽世,會(huì)增加過(guò)渡繪制的可能。Activity是依附在Window上的诡壁,如果給Activity設(shè)置了背景济瓢,并且沒(méi)有去掉window的背景,很容易導(dǎo)致過(guò)渡繪制妹卿;這里還有一個(gè)坑旺矾,有的應(yīng)用為了避免程序冷啟動(dòng)時(shí)出現(xiàn)黑屏/白屏的問(wèn)題,在主題中給window設(shè)置了背景夺克,并且在Activity的布局中給Activity也設(shè)置了背景箕宙,這會(huì)導(dǎo)致當(dāng)前界面存在兩個(gè)背景,占用了雙倍的內(nèi)存铺纽,并且還會(huì)有過(guò)渡繪制的問(wèn)題柬帕。程序啟動(dòng)黑屏應(yīng)該去優(yōu)化性能問(wèn)題,而不是采用給window設(shè)置背景的方式狡门;
??解決方案:可以通過(guò)給Activity自定義主題陷寝,在主題中去掉window的默認(rèn)背景,即:@null其馏;
(11) 類(lèi)的finalize方法調(diào)用時(shí)機(jī)不確定:
??問(wèn)題現(xiàn)象:程序隨機(jī)崩潰凤跑;
??原因分析:多個(gè)地方用到了同一個(gè)類(lèi),該類(lèi)用于對(duì)數(shù)據(jù)的IO操作尝偎,打開(kāi)文件后并沒(méi)有立即關(guān)閉饶火,也沒(méi)有釋放資源的public方法,主要通過(guò)類(lèi)的finalize方法關(guān)閉文件致扯,釋放資源肤寝;
??解決方案:finalize方法的調(diào)用時(shí)機(jī)是不確定的,不要指望通過(guò)該方法釋放與類(lèi)相關(guān)的資源抖僵,避免出現(xiàn)隨機(jī)的bug鲤看;
(12) Fragment isAdded:
??問(wèn)題現(xiàn)象:程序隨機(jī)崩潰;
??原因分析:跟蹤異常log發(fā)現(xiàn)耍群,是因?yàn)镕ragment沒(méi)有完全顯示或者已經(jīng)離開(kāi)Fragment的情況下义桂,導(dǎo)致的異常,這類(lèi)異常的主要原因是:使用Fragment時(shí)蹈垢,通過(guò)異步操作(比如回調(diào)慷吊、非UI線程等)更新Fragment的狀態(tài),但此時(shí)Fragment沒(méi)有完全顯示或者已經(jīng)離開(kāi)Fragment曹抬;
??解決方案:在調(diào)用Fragment的方法之前溉瓶,強(qiáng)烈建議調(diào)用isAdded方法判斷Fragment是否依附在Activity上,避免出現(xiàn)異常。
(13) Fragment hide堰酿、show被調(diào)用時(shí)疾宏,生命周期不會(huì)回調(diào):
??問(wèn)題現(xiàn)象:同一界面不同F(xiàn)ragment之間切換時(shí),并沒(méi)有觸發(fā)一些動(dòng)態(tài)效果触创,比如播報(bào)音頻坎藐、顯示切換動(dòng)畫(huà)等;
??原因分析:Fragment hide哼绑、show被調(diào)用時(shí)岩馍,系統(tǒng)并不會(huì)調(diào)用Fragment的生命周期回調(diào);
??解決方案:不同F(xiàn)ragment之間切換時(shí)凌那,主動(dòng)調(diào)用各個(gè)Fragment的生命周期回調(diào)兼雄;
2.使用不當(dāng)造成的坑##
(1) 9圖不要用tinypng壓縮:
??問(wèn)題現(xiàn)象:使用壓縮工具壓縮9圖后,顯示變形帽蝶;
??原因分析:9圖除了圖片信息外赦肋,還存儲(chǔ)一些Android在顯示9圖過(guò)程中需要用到的必要信息,通過(guò)壓縮工具壓縮圖片會(huì)改變文件的信息励稳,9圖被壓縮后程序能顯示佃乘,但顯示的效果無(wú)法達(dá)到預(yù)期,因?yàn)槔煨畔G失了驹尼。
??解決方案:9圖文件本身就不大趣避,沒(méi)必要壓縮;
(2) 同一設(shè)備上新翎,相同程序的圖片放在不同drawable文件夾下程帕,占用內(nèi)存不一樣:
??問(wèn)題現(xiàn)象:程序剛啟動(dòng)就占用了很高的內(nèi)存;
??原因分析:圖片放置位置不合理導(dǎo)致的地啰,程序在不同的設(shè)備中運(yùn)行時(shí)愁拭,會(huì)根據(jù)設(shè)備的分辨率和屏幕密度去從與之分辨率匹配的資源文件夾中取圖片,如果沒(méi)有對(duì)應(yīng)分辨率的文件夾亏吝,則從相近分辨率的文件夾中取岭埠,但圖片會(huì)被拉伸到當(dāng)前設(shè)備屏幕的寬高,所以會(huì)存在圖片被放大或者縮小的問(wèn)題蔚鸥,導(dǎo)致占用內(nèi)存會(huì)隨之變化惜论,具體可以查看這篇博客關(guān)于Android中圖片大小、內(nèi)存占用與drawable文件夾關(guān)系的研究與分析(http://blog.csdn.net/zhaokaiqiang1992/article/details/49787117)止喷;
??解決方案:為了減少UI的工作量馆类,并且減少APK的內(nèi)存占用的方法是讓UI出一套高分辨率版本的圖片,放在hdpi文件夾下弹谁。
(3) Adapter ViewHolder緩存導(dǎo)致顯示錯(cuò)亂的坑:
??問(wèn)題現(xiàn)象:ListView每一項(xiàng)在滑動(dòng)的過(guò)程中內(nèi)容顯示錯(cuò)亂蹦掐;
??原因分析:在Adapter的getView方法中通過(guò)position更新每一項(xiàng)的內(nèi)容時(shí)技羔,對(duì)于根據(jù)判斷條件給每一項(xiàng)設(shè)置屬性的情況,每個(gè)判斷條件下都需要給每一項(xiàng)的每個(gè)屬性賦值卧抗,否則在滑動(dòng)ListView或GridView時(shí)會(huì)導(dǎo)致內(nèi)容錯(cuò)亂;
??解決方案:在getView方法里面鳖粟,給每一項(xiàng)都要設(shè)置對(duì)應(yīng)的屬性社裆,比如給每一項(xiàng)的頭像設(shè)置圖片,如果某一項(xiàng)沒(méi)有頭像向图,不能不設(shè)置泳秀,應(yīng)該設(shè)置為透明,否則會(huì)錯(cuò)亂榄攀。
(4) Toast連續(xù)顯示時(shí)長(zhǎng)時(shí)間不消失:
??問(wèn)題現(xiàn)象:多個(gè)Toast同時(shí)顯示時(shí)嗜傅,Toast一直顯示不消失,退出程序了仍然顯示檩赢;
??原因分析:看Toast的源碼可以發(fā)現(xiàn)吕嘀,同時(shí)顯示多個(gè)toast時(shí)是排隊(duì)顯示的,所以才會(huì)出現(xiàn)同時(shí)顯示多個(gè)Toast時(shí)很久都不消失的情況贞瞒;
??解決方案:這屬于體驗(yàn)問(wèn)題偶房,很多應(yīng)用都存在。建議定義一個(gè)全局的Toast對(duì)象军浆,這樣可以避免連續(xù)顯示Toast時(shí)不能取消上一次Toast消息的情況(如果你有連續(xù)彈出Toast的情況棕洋,避免使用Toast.makeText);
(5) build.gradle中的versionName和versionCode:
??問(wèn)題現(xiàn)象:從Eclipse轉(zhuǎn)到AS的項(xiàng)目乒融,在機(jī)器上運(yùn)行時(shí)報(bào)版本比之前APK版本低的錯(cuò)誤掰盘;
??原因分析:從Eclipse轉(zhuǎn)到AS的過(guò)程中,如果你是通過(guò)AS直接新創(chuàng)建的一個(gè)工程赞季,注意模板會(huì)在build.gradle中給程序設(shè)置默認(rèn)versionName和versionCode為1愧捕,如果AndroidManifest.xml中的versionCode、versionName比build.gradle中的更高碟摆,會(huì)導(dǎo)致因?yàn)榘姹締?wèn)題安裝不上的情況(報(bào)INSTALL_FAILEDVERSIONDOWNGRADE錯(cuò)誤)晃财;
??解決方案:只在build.gradle中設(shè)置版本名和版本號(hào);
(6) AS中依賴(lài)包的動(dòng)態(tài)更新:
??問(wèn)題現(xiàn)象:依賴(lài)包頻繁更新典蜕,因?yàn)锳S編譯有緩存断盛,每次更新都需要修改依賴(lài)包的版本號(hào),特別麻煩愉舔,特別是依賴(lài)關(guān)系比較復(fù)雜的情況下钢猛;
??解決方案:在AS中,如果你想動(dòng)態(tài)同步一個(gè)依賴(lài)包的更新轩缤,可以在依賴(lài)包的最后面寫(xiě)上“+”命迈,比如:compile 'com.android.support:appcompat-v7:23.0.+' 贩绕,但這種方法需要謹(jǐn)慎使用,否則會(huì)因?yàn)橐蕾?lài)包的變動(dòng)導(dǎo)致你的項(xiàng)目不穩(wěn)定:Don't use dynamic versions for your dependencies
(https://link.zhihu.com/?target=http%3A//blog.danlew.net/2015/09/09/dont-use-dynamic-versions-for-your-dependencies/)壶愤;
(7) AS中同一個(gè)工程module太多導(dǎo)致編譯慢:
??問(wèn)題現(xiàn)象:編譯一個(gè)工程要好幾分鐘淑倾,特別是clean的時(shí)候,經(jīng)常10分鐘以上征椒;
??原因分析:其實(shí)這個(gè)很好理解娇哆,每個(gè)module中都有一個(gè)build.gradle,編譯的時(shí)候勃救,每個(gè)module的build.gradle中的task都需要執(zhí)行碍讨,所以編譯時(shí)間會(huì)很長(zhǎng)。
??解決方案:要解決這個(gè)問(wèn)題很簡(jiǎn)單蒙秒,將不經(jīng)常變動(dòng)的module打包成aar勃黍,主工程依賴(lài)aar而不是module,這樣避免了每次都需要重新編譯module的情況晕讲。
(8) 頻繁的GC操作導(dǎo)致程序卡頓:
??問(wèn)題現(xiàn)象:通過(guò)AS Monitor觀察應(yīng)用運(yùn)行過(guò)程中的內(nèi)存抖動(dòng)厲害覆获,通過(guò)GPU呈現(xiàn)模式觀察每一幀的曲線差別很大,整體感受程序運(yùn)行時(shí)不流暢益兄;
??原因分析:在2.3之前GC操作是不能并發(fā)進(jìn)行的锻梳,也就是系統(tǒng)正在進(jìn)行GC程序就只能阻塞住等待GC結(jié)束,在2.3之后GC操作改成了并發(fā)的方式進(jìn)行净捅,GC過(guò)程中不會(huì)影響程序的正常運(yùn)行疑枯,但在GC操作的開(kāi)始和結(jié)束還是會(huì)短暫阻塞一段時(shí)間,所以頻繁的GC會(huì)導(dǎo)致使用應(yīng)用的過(guò)程中卡頓蛔六。
??解決方案:為了應(yīng)用在使用過(guò)程中更流暢荆永,需要盡量減少觸發(fā)GC操作,這涉及到性能優(yōu)化国章,對(duì)于靜態(tài)代碼的分析具钥,AS已經(jīng)很強(qiáng)大了,可以使用Android Studio的Analyze→Inspect Code...進(jìn)行分析液兽;
(9) TextView 的setText方法骂删,如果傳入一個(gè)數(shù)字會(huì)直接當(dāng)作字符串資源ID處理:
??問(wèn)題現(xiàn)象:程序運(yùn)行時(shí)報(bào)“NotFoundException”異常;
??原因分析:TextView.setText(int value)的傳值有問(wèn)題四啰,在xml文件中沒(méi)有找到id對(duì)應(yīng)的字符串宁玫;
??解決方案:給TextView設(shè)置文本的時(shí)候一定要轉(zhuǎn)成String或者Charsequence類(lèi)型,避免TextView將setText中的參數(shù)當(dāng)做字符串資源ID處理柑晒,去加載字符串資源欧瘪,因?yàn)樽址趚ml文件中不存在導(dǎo)致程序運(yùn)行時(shí)崩潰。
(10) 通過(guò)反射訪問(wèn)方法和字段的效率大不一樣:
??問(wèn)題現(xiàn)象:程序運(yùn)行卡匙赞、慢佛掖;
??原因分析:在一個(gè)循環(huán)中使用到了反射妖碉,并且是調(diào)用的反射方法,改成反射字段后芥被,卡欧宜、慢的現(xiàn)象得到明顯的改善;
??解決方案:通過(guò)反射修改或者獲取類(lèi)中的某個(gè)屬性時(shí)拴魄,強(qiáng)烈建議使用訪問(wèn)字段的方式鱼鸠,不要使用訪問(wèn)方法的方式,這兩者之間的效率相差很大羹铅,親測(cè)訪問(wèn)方法是訪問(wèn)字段耗時(shí)的1.5倍,具體情況和類(lèi)的復(fù)雜度有關(guān)愉昆。
(11) .nomedia文件的使用:
??問(wèn)題現(xiàn)象:程序中的緩存文件在相冊(cè)职员、音樂(lè)播放器中顯示;
??原因分析:相冊(cè)跛溉、音樂(lè)播放器等多媒體應(yīng)用是讀取媒體庫(kù)中的數(shù)據(jù)焊切,而程序的緩存文件被緩存到了媒體數(shù)據(jù)庫(kù)中;
??解決方案:如果你希望自己應(yīng)用生成的數(shù)據(jù)不被媒體庫(kù)掃描到芳室,應(yīng)該在生成數(shù)據(jù)的文件夾下創(chuàng)建一個(gè)名為".nomedia"的隱藏文件专肪,避免出現(xiàn)一些無(wú)意義的文件也被媒體庫(kù)掃描到的情況,比如APP的緩存圖片在相冊(cè)中顯示堪侯、宣傳視頻在視頻播放器中顯示嚎尤、音效在音樂(lè)播放器中顯示等。
(12) 循環(huán)動(dòng)畫(huà):
??問(wèn)題現(xiàn)象:在不待機(jī)的情況下伍宦,長(zhǎng)時(shí)間處于一個(gè)界面時(shí)芽死,手機(jī)發(fā)燙;
??原因分析:界面中存在循環(huán)動(dòng)畫(huà)次洼,CPU关贵、GPU一直在工作;
??解決方案:循環(huán)動(dòng)畫(huà)會(huì)導(dǎo)致界面一直在刷新卖毁,CPU揖曾、GPU持續(xù)工作,會(huì)有功耗問(wèn)題亥啦,建議拒掉這種視覺(jué)呈現(xiàn)效果炭剪。
(13) 謹(jǐn)慎使用aaptOptions.cruncherEnabled = false;
aaptOptions.useNewCruncher = false;
??問(wèn)題現(xiàn)象:編譯生成的APK文件特別大,超過(guò)了正常的大薪啤念祭;
??原因分析:解壓APK發(fā)現(xiàn),主要是圖片資源導(dǎo)致碍侦,將APK中的res文件夾和源碼下的res文件夾對(duì)比粱坤,發(fā)現(xiàn)多了很多圖片文件隶糕;跟蹤原因發(fā)現(xiàn)最新的buildtools對(duì)資源文件的檢測(cè)很?chē)?yán)格,對(duì)于Eclipse轉(zhuǎn)AS的項(xiàng)目站玄,很多時(shí)候都是因?yàn)閳D片問(wèn)題導(dǎo)致在AS上編譯不過(guò)枚驻,比如將jpg強(qiáng)轉(zhuǎn)為png在AS上就編譯不過(guò),在項(xiàng)目中可以在build.gradle中加上這兩句:aaptOptions.cruncherEnabled = false;aaptOptions.useNewCruncher = false株旷,屏蔽掉aapt對(duì)圖片的嚴(yán)格檢測(cè)再登。但需要謹(jǐn)慎使用這兩個(gè)屬性,否則可能會(huì)導(dǎo)致編譯生成的APK特別大(解壓生成后的APK發(fā)現(xiàn)晾剖,對(duì)于有問(wèn)題的圖片锉矢,每個(gè)drawable文件夾下都會(huì)拷貝一份);
??解決方案:去掉屬性設(shè)置齿尽,解決編譯問(wèn)題沽损。
3.開(kāi)源項(xiàng)目中的坑##
FancyCoverFlow: 這個(gè)控件在API高于16的設(shè)備中,滑動(dòng)的過(guò)程中會(huì)強(qiáng)制刷新一遍循头,導(dǎo)致切換和初始化的時(shí)候都很卡绵估,當(dāng)時(shí)覺(jué)得這個(gè)效果挺好,后來(lái)用上之后這個(gè)控件成了性能瓶頸卡骂;
Fresco: 這個(gè)控件用起來(lái)特別爽国裳,唯一的缺陷的相比于相同功能的其它開(kāi)源項(xiàng)目(Glide、Picasso)全跨,體積過(guò)大缝左;
ActiveAndroid: 這個(gè)輕量級(jí)的數(shù)據(jù)庫(kù)框架也挺好用,但缺陷是初始化耗時(shí)螟蒸,可以看一下這篇文章:在Android中使用反射到底有多慢盒使?
JXL: 一個(gè)讀寫(xiě)Excel文件的開(kāi)源庫(kù),用起來(lái)很方便七嫌,但有個(gè)問(wèn)題:文件大小超過(guò)5M直接掛掉少办;
JPinyin: 漢字轉(zhuǎn)拼音的一個(gè)工具庫(kù)票摇,APK加密后這個(gè)庫(kù)不能正常使用托修,后來(lái)查出是因?yàn)轫?xiàng)目中數(shù)據(jù)的問(wèn)題进泼,加密后數(shù)據(jù)的內(nèi)容變化了险绘,最后只能自己改造坛善,將數(shù)據(jù)按照我們自己的方式處理趾痘。