早上5點自然醒,寫下第一篇總結(jié),引來很多人的關(guān)注,一些人跟我要github上的源碼,非常的抱歉啊,雖然公司解散了,但那些資產(chǎn)還是需要保密的,于情于理都不能公開給大家;不過附上我的Github帳號 https://github.com/SwordBearer,互粉吧 ;) ,在接手這款即時通訊開發(fā)后,個人還是學(xué)到了很多東西,歡迎一起來交流交流。
現(xiàn)在從開發(fā)層面說說自己遇到的事吧,3月份接手這個項目,還有另外一位同事(比我早畢業(yè)一年),我們兩個人一起開發(fā)。如果叫我一句話介紹當(dāng)時對這項目的感覺,那只有三個字:一坨屎。 Android項目初期就是幾個新手在做,從一開始就沒有個好底子,隨后又經(jīng)手了四五撥人,往上不斷堆積,給整個項目積攢了無數(shù)問題:
1.這幾撥人最大的共同點就是:幾乎不寫注釋!,代碼干干凈凈!不多一行也不少一行!
2.命名不規(guī)范,甚至Socket接口和包名,類名都不對應(yīng),連英文都有拼錯的,所有Fragment都寫成Flagment,這樣一兩處倒還好,關(guān)鍵是太多了。
以上兩個問題隨之帶來的結(jié)果就是出了BUG后,只能連猜帶讀去解決;可我覺得這都是一個程序猿最基本的常識啊,寫規(guī)范注釋,規(guī)范命名;
3.對于第三方庫的引用問題,以前的代碼中,凡是用到第三方庫,尤其是UI的,基本上是把整個項目代碼都copy進(jìn)主項目,順帶把一些文件前面的注釋都去了,并不是通過庫引用方式來使用,所以誰加進(jìn)來的UI控件,別人基本上不知道怎么用,因為沒有文檔。連最核心的WebSocket網(wǎng)絡(luò)連接代碼,也是從Github上扒下來,然后塞進(jìn)去,不加注釋,這就造成另外一個極其嚴(yán)重的問題,下文再述;
細(xì)細(xì)想想,這半年基本上都是在替人擦屁股,不過在重構(gòu)整個項目的過程中,還是學(xué)到了很多的東西,尤其是在性能和Socket連接上,收獲頗多;
Android性能存在很多問題,內(nèi)存占用大,點擊響應(yīng)慢,數(shù)據(jù)庫讀寫慢,UI繪制慢等等,接下來一一分析一下;
項目中有用到一個標(biāo)題欄,所有頁面中都會出現(xiàn),原來項目中,是定義了一個無比復(fù)雜的自定義控件,有左側(cè)返回按鈕,右側(cè)點擊按鈕,中間標(biāo)題,以及進(jìn)度條等等,所有頁面用這一個控件,由于使用了這個標(biāo)題欄,所有Activity的XML布局中就多了一層。這個標(biāo)題欄內(nèi)部又嵌套好幾層,而大多標(biāo)題欄只有左側(cè)返回按鈕和中間標(biāo)題欄,剩余的那些控件就隱藏起來,這樣夠兇殘吧,過度封裝害死人。如何改進(jìn)?我想大家都知道――ActionBar,移除原來所有的自定義標(biāo)題欄,布局中減少了層次,并且ActionBar擴(kuò)展性更高,可以顯示更多的操作,我沒有測試這個改進(jìn)會有多少ms的提升,但是一定會更快。
好多ListAdapter沒有使用復(fù)用原理!
有兩個問題著重說一下,一個是數(shù)據(jù)庫優(yōu)化,另外一個是Socket連接問題;
一,數(shù)據(jù)庫優(yōu)化
app中有一個場景是更新一系列聯(lián)系人,測試數(shù)據(jù)是780條(還包括112個分組,分組下的聯(lián)系人總共有780條),當(dāng)數(shù)據(jù)變化后,需要將原來的聯(lián)系人刪除,先保存分組到分組表,再將這780條插入聯(lián)系人表。當(dāng)時就在這一塊總是出現(xiàn)數(shù)據(jù)丟失的情況,一部分聯(lián)系人沒有保存,這是一個很嚴(yán)重的問題。問題就出在SQLite連續(xù)插入的地方,原代碼是如何插入的呢?數(shù)據(jù)庫打開,遍歷插入,然后關(guān)閉,最原始最簡單的方法,可是測試了一下,光780條數(shù)據(jù),用時20s,很恐怖的結(jié)果,20s,一段廣告都看完了。
所以這就演變成了一個很常見的問題:如何在SQLite中一次性插入大量數(shù)據(jù)?
方法1,開啟事務(wù),這是必須要做的,在for循環(huán)外開啟事務(wù),循環(huán)中插入數(shù)據(jù),循環(huán)結(jié)束關(guān)閉事務(wù)。這樣寫了之后,20s立馬變成了4s,當(dāng)時就震精了。原因:事務(wù)是在內(nèi)存中進(jìn)行處理,當(dāng)所有插入完成后,再一次性寫入數(shù)據(jù)庫,每一次寫入都是一次 IO操作,SQLite是個性能很低的數(shù)據(jù)庫,聽聞比文件操作的速度慢10倍左右(沒有具體進(jìn)行比較過)。
方法2,使用SqliteStatement,使用后效果杠杠的,至于為什么,可以參考這里 http://liuzhichao.com/p/1664.html ;
講方法1和方法2結(jié)合使用后(最外層開啟事務(wù),然后使用SqliteStatement操作,最后關(guān)閉事務(wù)),效果如何呢? 20s直接降到 1s 左右!而且1s 完全可以接受了;
二,Socket連接問題
做過即時通訊的人都知道(當(dāng)然我還是門外漢),客戶端需要一直保持一個socket長連接,并且要一直發(fā)送心跳來維護(hù)這個長連接,如果中斷了,需要重新請求連接。
我們的socket連接是放在一個單獨的thread里面去實現(xiàn)數(shù)據(jù)請求和接收的,這個設(shè)計本身其實是有問題的。首先,Android這種平臺,對內(nèi)存占用非常敏感,后臺的線程一不留神就會被系統(tǒng)kill掉,這就是我們?yōu)槭裁匆恢睌嗑W(wǎng)的最終原因;其次,socket長連接算是這個應(yīng)用中最低層,最核心的部分,所有的數(shù)據(jù)接收發(fā)送最終都是在這里處理,不應(yīng)該將它僅僅用一個線程來處理,不然在通訊過程中,遇到諸如鎖屏,網(wǎng)絡(luò)中斷,后臺運行等都有問題,當(dāng)初在重構(gòu)的時候是把它放在了一個Service里面,然后對socket在進(jìn)行定時心跳維護(hù)等等,此處涉及的比較多,就不展開了。
經(jīng)歷這個項目之后,我就在想,如何才能構(gòu)建一個高性能的Android架構(gòu)呢?看過INFOQ上分享的微信開發(fā)過程 點擊打開鏈接 ,著實讓人膜拜,一個龐大的系統(tǒng),也是一點點積累起來的,技術(shù),就是這么純粹,只需要時間和耐心去打磨而已。
說多了都是淚,公司倒了,項目停了,心里卻留下了一大段空白,有對技術(shù)的,也有對創(chuàng)業(yè)的,以后慢慢再敘述吧.........