遇到一個代碼混亂不堪的Android項目該怎麼辦?

轉載請註明出處:http://blog.csdn.net/asdzheng/article/details/49403155

好久沒寫博客,這段時間換了工作,有很多事情需要學習和處理,現在終於有點時間來總結這段時間所做的事情。新東家是一家創業不久,正處於上升期的公司,我進去時剛好在擴招了四五人,目的很明顯,我去之前也做好準備,上升期的公司應該有很多問題需要我去解決,也做好了應對初期留下各種髒亂代碼的的準備;

可想象畢竟是想象,等進到公司,將代碼遷移下來一看,儘管心中有備,還是抵不住的內心翻騰倒海腦海中無數只草泥馬蹦騰而過,這樣的代碼也行。下面我就把我看到的代碼總結一下:

問題總結

1、 同類型的處理,沒有抽象,造成代碼冗餘

Android項目中最常見的的無非是網絡接口請求,不同的業務對應不同的接口,處理流程就是 客戶端操作業務 —> 客戶端調用接口 –> 服務器接收請求 —> 處理完返回處理結果 —> 客戶端接收結果 —> 客戶端對結果做處理和顯示; 這樣一套流程,最常見的方式就是封裝一套網絡請求框架,業務代碼只關注請求時傳入對應接口關鍵字和參數,然後寫幾個回調方法等着接收數據就好。

但之前我們的框架並不是這樣,每調一次接口都要新建兩個方法,然後調用和處理代碼一般都要寫個100-200行模板代碼,這框架直接導致的結果是,每個有請求網絡的Activity,代碼都至少要500行以上,大部分的界面都是上千行規模,可想而知,要熟悉這樣的代碼得多辛苦。

2、 不考慮性能,代碼只要能用就行

例如數據存儲,Android其實提供了4種不同的本地存儲方式,特點各不相同,各有各得優劣勢,適用於不同場景,這不做分析。這四種方式裏,我想最容易使用當然是SharePrefences,沒錯,就是因爲它容易使用,APP裏的的所有存儲都只用它,把它當作萬能且用法極不規範。其中一點就是用它來保存大量列表對象,最大的一個數據保存完xml文件直接快100KB,如果要在這數據上做些增刪改想想都覺得酸爽,但以前就是這麼幹的!不止如此,對於從prefence裏拿數據的開銷,此前根本就沒在乎過,大量的如下代碼:

if (PrefenceUtil.getD() != null) {
        if (PrefenceUtil.getD().getD1() != null) {
            if (PrefenceUtil.getD().getD1().getD2() > PrefenceUtil.getD().getD1().getD3()) {
                doSomething();
            }
        } else {
                doSomething();
        }
    } else {
        doSomething();
    }

其中PrefenceUtil.getD()是從sharePrefences裏拿去拿數據,可以看到,一個判斷,就操作了xml文件4次。

3、代碼不規範,命名隨意,到處的魔鬼數字

  • 大部分參數沒有設置爲private
  • 幾乎沒有註釋,複雜邏輯代碼只能靠猜
  • 佈局的變量名沒規則,例如每一個佈局裏的按鈕都叫btn,代碼裏一關聯上百個文件出來
  • 到處startActivityForResult(intent, 1001), 和setResult(1003)…
  • 工具有FileHelp有FileUtil…

4、相同的功能控件不做封裝,每用到一處,複製一處

其中有一個條件篩選框,快上千行代碼,邏輯複雜很容易出錯,而且用處的地方很多,但是之前就是能夠忍受,反正就是copy、copy、copy

以上這幾點,每點都有無數的例子可拎出來暴屍幾天,供大家笑話,但壞代碼不重要,除非大公司有非常好的代碼審覈機制,不然壞味道的代碼哪都能找出來,下面纔是重點,面對這些代碼時我們該用什麼辦法改進它們,讓以後避免再出現這樣的代碼纔是關鍵;

問題處理

1、針對我們項目的一些通用操作,我做了一些抽象:

  • 完備BaseActivity和BaseFragment和BasrAdapter,這三個抽象基類在Android項目真是太重要了,把這三個基類完善好,會讓每個具體的業務界面少寫幾百行代碼,而且不易出錯,出錯了又可根據業務需求統一界面修改和優化。以BaseActivity爲例,我在裏面放了請求接口的入口回調和銷燬,TitleBar的統一構建,統一的錯誤頁面和顯示頁面等等。

  • 將以前那個不知從哪裏來的網絡請求框架改爲Volley,然後針對我們接口的做了自定義封裝,例如通用參數底層封裝好,請求前顯示加載框,請求響應後消失,將網絡回調分爲三種類型,請求成功,請求數據異常和網絡異常,具體業務根據請求結果做不同處理。

  • 建立類庫,我們有三個項目,一主兩副,以前各自爲政,在我抽象了基礎類和網絡請求框架,發佈了兩個版本發現效果很好後,我就着手創建了類庫項目,讓這些每個項目都要用到的東西和一些自定義控件工具類放在類庫裏,讓所有項目都能享受到我們優化和改進過的代碼成果。

  • 當然還有一些比較細碎的抽象,如將類保存爲數據庫時都要經過一些列步驟的轉換和解碼轉碼爲String類型在保存,更痛苦的是這些操作每個類都要來一次,我把它抽象成一個方法,然後再做一些優化。

2、性能的優化

  • 由於之前的數據都是統一保存在prefence裏,現在一下子要換成別更合理的方式保存,要做的工作和測試量會比較大,在沒有充足的時間下,不敢輕易更換存儲方式。我分析了一下數據存儲和獲取的主要性能瓶頸是在那幾個常用的和數據量比較大的類,像問題2舉得例子,比較省時間的和立竿見影的優化方法,並不是先用一個變量來接收prefence裏的值
    Data data = PrefenceUtil.getD() 然後再用data去做判斷。這樣做只會讓一處地方得到優化,遇到一處改一處,只會忙死,更好的辦法是優化PrefenceUtil.getD()方法裏的內容。我把那幾個數據量大的類,都用靜態類緩存起來(佔用內存並不大,可能比以前更省內存,因爲不用每次都new 出來好多類和數據流),這樣只需在進入歡迎頁時,獲取一次,以後都從內存區域拿就好,這樣所有用到的方法都能得到優化。(當然還有去掉一些根本不需要保存在prefence裏的類,只需靜態緩存就可以)

  • 優化了progressbar,這傢伙也是到處再用到,但之前項目爲了酷炫,從github上搞來一個Material Design效果的progressBar,效果雖炫,但是有些情況下卻非常卡,看了一下日誌才知道,這圈圈一轉,後臺日誌就能看到在瘋狂的GC。我看了源碼才知道,這傢伙,在onDraw()裏new Bitmap(),能不耗內存跟cpu嗎。後來經過幾天的調研和分析,對比了不同的progressbar,最後發現還是用原生的最好(holo風格也不難看),第三方不是內存和cpu佔有率過高,就是有些機器不兼容,酷炫效果雖好,但也不能爲了效果犧牲太多性能。

  • 把首頁之前在首頁加載的一些非即時性接口放到了歡迎頁加載,以前所有接口都是等到進到首頁才調起,請求完所有接口再顯示界面,結果可想而知,首頁每次都要等個幾秒才能看到,調整了一下,效果還是很明顯,速度快了很多。

3、 代碼規範

相較於前兩個優化,這是最難的。前面兩個你只要有時間,就可以動手幹,但代碼規範是需要你整個團隊配合,和一套代碼審覈流程才能做好的事。這種團隊協作的事,如果老員工不遵守或者主管沒有強力實行,靠我這樣一個有代碼潔癖的新同事來勸,效果肯定不怎樣,大家還會怎麼方便怎麼來。我只能保證在我完成的所有功能裏,做到規範,然後看到一些極不合理的地方,在羣裏拿出來鞭打一下,好言好語懇求大家以後不要這樣,邏輯複雜的地方多點註釋。。。(不過最近話事人被我的整潔代碼打動了,在會上要求大家以後都照着我的風格來寫。PS: 我也沒什麼風格,谷歌和Java的一些常見規範而已,只是大家都遵守並不易)

4、控件封裝

之前說的progrssbar算一個,還有個主要的就是下拉刷新和下拉加載更多控件,因爲這個好多地方用到,一個APP裏好幾種下拉刷新效果顯然不是一個靠譜公司該乾的事,我github上選了一個還算可以得框架(它是封裝了swiperefreshlayout加上下拉加載),自己完善了一下,改進了一些bug,加上了延遲消失加載框功能,現在公司所有需要下拉刷新的地方已經統一成我的這一款,內心還是很欣慰的,畢竟自己的努力一直能得到別人的認可。

針對這篇博客提出的問題說我幾點建議

無論代碼多爛性能多遭,只要代碼能夠正常編譯,App還能正常運行,在時間充裕的情況下就不是什麼事。只是選擇優化和重構時需要注意一些點:

  • 最先優化和重寫那些最常用的代碼,如Android項目裏的網絡請求部分,幾乎是每個界面都會用到的。

  • 如果沒有專門一個版本來優化性能,那就先高質量的完成你即將要開發的新功能或者重構好你要維護的就功能。

  • 看不懂的代碼先不動,如果有些舊代碼實在搞不清楚,老員工也說不出所以然,這樣的代碼先留着,也可以先用一個wapper方法封印起來,等有足夠時間才一句句調試它。

  • 善於利用久項目裏留下的那些問題不大的代碼,例如之前寫的一些工具幫助類,如果沒有發現大的性能問題,裏面代碼寫得差一點沒關係,這些代碼先用着,優化等級可放在最低。

  • 多從架構方面(這需要你有的抽象編程能力)方面入手,具體代碼的優化既耗時測試工作量大,一般沒有那麼多時間可折騰,最有效的方法是搭一個架子,然後具體功能按照你提供的接口往裏填參數就可。例如每個Activity,一般都用統一樣式TitleBar,你可以將TitleBar封裝在BaseActivity裏,然後提供一個自定義TitleBar的接口,默認就用你提供的TitleBar,這樣大部分TitleBar的代碼都是控制在基類裏,出不了大問題。

  • 對於像網絡請求,下拉刷新控件,圖片顯示框架這些通用功能,能用原生的儘量使用原生的,沒有再考慮第三方框架,使用第三方框架也找那些比較多人使用和作者一直維護的框架,不到萬不得已不要自己寫,再不濟也可以拿來改嘛。另外,一旦你使用了框架,就要熟悉它,作者的wiki的一定是要看的,有時間也要看看源碼,不然出問題了很容易找不到北。

最後說點實際的,上面的這些建議都是建立在你的公司願意在優化代碼和性能這上面花時間的情況下才有用,如果只是說說而已,開發時間掐得死死,不留空隙的逼你們開發新功能,完全不考慮性能代碼質量,那上面的建議都將作廢,以下的建議可能才最有用:

多到100Offer,拉鉤,51job,獵聘網,內推網看看。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章