1. 程式人生 > >如何打造一款高質量的Android移動應用

如何打造一款高質量的Android移動應用

隨著移動網際網路紅利的結束,移動應用開發的爆發期已經結束,現在已經進入穩定期,現在大家講得最多是使用者體驗和應用質量,現在各種移動應用功能同質化很嚴重,所以如何打造出一款高質量的移動應用是留住使用者的的先決條件。

過去的 iOS 開發者可能做夢也想不到,現在也要開始適配螢幕和雙卡雙待,更不用說Android那麼多如繁星的機型,廠家和作業系統,如果應用要出海,還要面對幾十個國家不同的語言和環境。另一方面,我們的業務越來越複雜,如何管理上十幾個上百個模組,以及還要面對React Native,Flutter,Kotlin,Tensorflow等各種語言跟框架堆積在一起的情況,所以做一款高質量的應用需要做很多的工作。一個應用至少要經過開發,編譯CI,測試,灰度和釋出幾個階段,見如下圖所示:

除了在開發測試以及灰度階段對應用進行分析外,應用一旦安裝到使用者手機上後對使用者操作資料的分析才是最難捕獲的,所以選擇一款成熟穩定的移動端APM(Application Performance Management)平臺是我們分析資料的堅實後盾,國內像阿里,騰訊,美團點評,餓了麼,愛奇藝這些大廠都在大力投入研發應用效能管理平臺。Google今年也發力Android Vitals監控,新增了耗電,許可權管理等模組。

移動APM質量平臺好處

1、統一管理,所有階段的異常資料都彙總到一個平臺;

2、統一三端,現在大部分應用都由Android,IOS,H5多個端組成,隨著技術的發展還可能增加React Native,Flutter,Kotlin等新技術模組的監控,所以統一各個端非常重要。

移動應用的質量主要包括穩定性和效能,像崩潰,卡死,白屏這些問題對於使用者而言是致命的,另一大類問題就是效能問題,安裝包大小,啟動,耗時,耗電,流量等範疇,具體分類如下:

由於Android碎片化和國內Android生態的亂象,手機廠商的隨便定製ROM,導致國內Android應用需要對各個廠商的手機進行適配,在今年11月份舉辦的Android綠色聯盟開發者大會上推出的應用體驗標準,對應用的相容性,穩定性,效能,功能和安全做了詳細的定義,我們可以根據這組資料對我們的Android應用進行優化。

雖然移動APM質量平臺可以幫助我們快速發現和定位問題,但是監控不能保證實現高質量,這裡還需要程式設計師進行分析和優化,根據上面提到的移動應用質量指標,本文從崩潰,記憶體優化,卡頓定位和分析,以及應用啟動等幾個方面淺談一下如何進行優化。

Android app崩潰率可以用:UV崩潰率=發生崩潰的UV / 登入UV,只要使用者發生過一次崩潰就會被計算到。

1、Android崩潰分類:

1、java崩潰;

2、Native崩潰。

簡單來說,Java崩潰就是在Java程式碼中,出現了未捕獲異常,導致程式異常退出,Java崩潰相對來說比較容易捕獲。在Android系統中有一個UncaughtExceptionHandler類,可以在uncaughtException回撥函式中對異常進行捕獲然後上報到APM質量平臺。但是Native崩潰會比較麻煩,Native崩潰一般是在c/c++程式碼中訪問了非法地址,也可能是地址對齊出現了問題,或者發生了程式主動abort,這些都會產生signal訊號,導致程式異常退出。

2、Native崩潰的捕獲流程:

1、編譯階段:編譯c/c++的時候需要把符號資訊保留下來;

2、客戶端,捕獲到異常的時候,儘可能地將有用的資訊儲存到本地,然後選擇適當的時機上報伺服器;

3、服務端,讀取客戶端上報的日誌檔案,尋找的的符號檔案,生成可讀的c/c++呼叫棧。目前Native崩潰捕獲最成熟的方案就是google的breakpad方案,在github上git clone https://github.com/google/breakpad.git ,可以在Linux或者mac平臺上編譯出minidump_stackwalk,dump_syms工具。通過dump_sysm工具可以生成發生崩潰so檔案的符號表,通過mindump_stackwalk工具可以生成上報native崩潰日誌的呼叫棧,結合符號表就能定位到發生崩潰的位置。

崩潰處理

1、Java崩潰型別比較明顯,實際開發過程中NullPointerException空指標的情況比較多,從後臺獲取的資料沒有判空就就進行使用等情況容易產生空指標異常,或者OutOfMemoryError,使用了大圖片沒有及時釋放導致記憶體耗盡;

2、Native崩潰需要觀察signal,code,fault addr等資訊;

3、ANR的時候先看主執行緒的堆疊,是否因為鎖等待導致,接著看ANR日誌檔案中iowait、CPU、GC、system server等資訊,進一步確定是I/O問題,或者是CPU競爭問題,還是由於大量GC導致卡死。

記憶體優化

記憶體優化是崩潰優化中非常重要的一個部分,類似OOM,很多的異常退出都是由於記憶體問題引起的。記憶體引起的第一個問題就是異常,包括OOM,記憶體分配失敗,記憶體整體不足引起應用被殺死;記憶體造成的第二個問題是卡頓,java記憶體不足會引起頻繁地GC,除了頻繁GC造成卡頓外,實體記憶體不足會引起系統觸發low memoery kill機制。

記憶體優化主要從以下三個方面入手

1、裝置分級;

2、bitmap優化;

3、記憶體洩漏。

Facebook 開發的檢測手機主流配置工具device-year-class,我們可以對低端手機關閉複雜的動畫效果,使用565格式圖片,使用更小的快取策略來提升應用在低端機上的體驗。

根據以上的裝置記憶體分配圖,可以使用一下程式碼,根據不同裝置使用不同的動畫顯示策略。

if (year >= 2013) {
 // Do advanced animation
} else if (year > 2010) {
 // Do simple animation
} else {
 // Phone too slow, don't do any animations
}
複製程式碼

一個空的程序也會佔用10MB的記憶體,所以在低端機器上儘可能減少應用啟動程序數,減少常駐程序數,儘量不要使用程序保活技術。一個80MB的應用很難在512MB記憶體的手機上流暢地執行起來,可以針對低端機使用者推出輕量版本,比如facebook Lite,今日頭條極速版本都是這個思路。

Bitmap記憶體一般佔據應用總記憶體很大一部分,把bitmap放到native記憶體,雖然可以減少GC頻繁呼叫帶來的問題,提高了系統記憶體利用率,但是並不能解決bitmap佔用記憶體過大的問題。Bitmap優化前提就是限制圖片的呼叫,即限制Bitmap.createBitmap,BitmapFactory相關介面的呼叫,可以考慮使用統一的圖片庫比如Glide,Fresco等。檢測大圖片,例如長寬遠遠大於view甚至螢幕的寬高,就需要對這個大圖片進行優化,重複圖片監控,如果多個bitmap的畫素資料完全一致,就應該刪除冗餘的圖片。記憶體洩漏,應該從架構上進行設計,例如,避免長週期的物件持有短週期物件,各種監聽器儘量不要引用Activity或者Fragment的context。Java記憶體洩漏可以藉助類似LeakCanary自動化檢查工具,可以做到Activity和Fragment的記憶體洩漏檢查。

應用卡頓都和CPU時間相關,CPU時間分為兩種:使用者時間和系統時間。使用者時間是應用程式執行程式碼消耗的時間;系統時間是執行核心系統呼叫所消耗的時間,包括I/O、鎖、中斷以及其他系統呼叫時間。通過cat /proc/stat得到整個系統CPU的使用情況,然後通過cat /proc/[pid]/stat獲取某個程序的CPU使用情況,如果CPU使用率長期大於60%,標識系統處於繁忙狀態,就需要進一步分析使用者時間和系統時間的比例。對於普通的應用程式,系統時間一般不會超過30%,如果超過這個值,就需要進一步檢查是不是I/O過多,或者是其他系統呼叫問題。

Andriod卡頓排查的主流工具

1、Traceview;

Traceview利用Android Runtime函式呼叫的event事件,將函式執行的耗時和呼叫關係寫入trace檔案,此工具本身有很大的效能開銷,有時無法真是反應實際情況,比如一個函式本身耗時1秒,但是Traceview工具開啟後可能變成了5秒。

2、Nanoscope;

Nanoscope是uber開源的工具,它直接修改Android虛擬機器原始碼,在ArtMethod執行入口和執行結束位置增加埋點程式碼,將所有資訊寫入到記憶體,等到trace結束統一生成結果檔案,它不會帶來額外的效能開銷,可以任意分析一個應用,但是需要自己刷ROM,目前只支援Nexus 6P。

3、systrace;

Systrace利用Linux的ftrace工具,在系統各個關鍵位置增加了監控埋點,可以對Graphics,Activity Manager,Dalvik VM,System server進行監控,而且效能開銷非常低,但是它不支援應用程式程式碼耗時分析,使用起來有一定的侷限性。

4、Simpleperf。

Simpleperf,可以分析Native函式耗時,它是Android5.0以後增加的效能分析工具,它可以監控dex,verify class等的耗時,在Android studio3.2可以直接在profiler中直接使用。總的來說卡頓分析的話,如果分析Native程式碼耗時,可以選擇simpleperf;如果想分析系統呼叫可以選擇systrace;如果想分析整個程式執行流程的耗時可以選擇traceview或者插樁版本的systrace。

Android APP啟動過程優化

Android APP啟動過程:

1、點選桌面圖示解析Manifest;

2、Application建立,閃屏Activity建立;

3、MainActivity主介面建立;

4、啟動完成介面可操作。

根據整個啟動流程我們可以把啟動優化分為:閃屏優化,業務梳理,業務優化,執行緒優化,GC優化和系統呼叫優化。

一般應用都會先建立SplashActivity,然後在建立MainActivity,如果能把兩個Activity合成一個,可以節省100ms左右的優化,通過MainActivity先展示SplashFragment,展示完畢有remove掉,同時在閃屏的2秒時間內進行首頁網路資料的快取,同時採用viewstub形式對activity_main的佈局進行懶載入,防止首頁過於複雜耽誤view的解析時間。

由於很多專案會使用外掛化,熱更新等技術,而這些框架會使用各種反射,各種HOOK技術,這是非常耗時的(平均需要幾百毫秒),所以應該對這些業務模組進行優化。

執行緒優化主要是減少CPU排程帶來的波動,應該控制執行緒數,執行緒太多會互相競爭CPU資源,統一的執行緒池來管理,根據機器效能控制執行緒數。另外可以利用systrace檢查是否有執行緒鎖,因為主執行緒會因為有執行緒鎖而等待,出現主執行緒長時間空轉。

啟動過程儘量減少GC次數,避免造成主執行緒長時間卡頓,通過systrace檢視整個啟動過程GC的時間,如果發現GC同步等待,那就需要使用allocation工具做進一步分析。

啟動過程中避免進行大量字串操作,特別是序列化和反序列化。一些頻繁的建立物件,比如在網路庫和圖片庫中byte陣列,buffer儘量重複使用。如果一些模組確實需要頻繁建立物件,可以考慮移到Native實現。通過systrace的System Service型別可以檢視System Server的CPU工作情況,在app啟動過程中,儘量不要做系統呼叫,比如PackageMangerService操作,Binder呼叫等等。

結語:

開一發一款高質量的應用涉及到的知識和內容比較多,本文基本上歸納總結了大致的方向,和一些實踐中的應用總結,把所有的方面都做到了,非常耗費人力和時間,但是我們可以把這個作為一個終極目標,不斷打磨產品,爭取為使用者帶來更好的移動體驗。

-END-

作者:周智       宜信技術學院官網:http://college.creditease.cn/#/index