在技術面試的時候確定都會問到使用了哪些第三方框架,爲何使用它而不用其餘的。身邊朋友就有這樣的親身經歷:java
面試官:大家項目中加載圖片都是用的什麼框架?
面試者:Glide啊(心裏竊喜)
面試官:爲何使用Glide而不用其餘的?
面試者:(沉默10s),Glide好啊,我比較喜歡。(心裏不安)
面試官:......(能不能好好聊天了)android
這篇博文主要就是針對日常使用到的框架作一個整理和分析其優劣。git
爲了從總體上進行把握,先來看看一個完整的APP總體架構github
從較高的層次將,一個APP的總體架構能夠分爲兩層,即應用層和基礎框架層。面試
應用層專一於行業領域的實現,例如金融、支付、地圖導航、社交等,它直接面向用戶,是用戶對產品的第一層感知。算法
基礎框架層專一於技術領域的實現,提供APP公有的特性,避免重複製造輪子,它是用戶對產品的第二層感知,例如性能、穩定性等。數據庫
一個理想的APP架構,應該擁有以下特色apache
基於以上設計原則,咱們能夠看出APP架構圖,最上層是應用層,應用層如下都屬於基礎框架層,基礎框架層包括:組件層、基礎層和跨平臺層。json
咱們要討論的重點是基礎層,下面開始一步一步地闡述如何基於開源函數庫搭建屬於本身的一個基礎技術堆棧。數組
首先要明確的是,咱們選擇開源函數庫或者第三方SDK、通常須要綜合考慮一下幾個方面
日誌記錄不管在服務端開發仍是移動端開發,都是一個基礎且重要的能力,開發人員在代碼調試以及錯誤定位過程當中,大多說都要依賴日誌信息,一個簡潔靈活的日誌記錄模塊是至關重要的。
Logger 是基於系統Log類基礎上進行的封裝,但新增了以下超讚的特性。
支持格式化輸出JSON、XML格式信息
Logcat截圖
固然Logger也不是完備的,它雖然支持格式化輸出JSON、XML,但並不支持諸如List、Set、Map和數組等常見Java集合類的格式化輸出。如何解決呢?能夠看下LogUtils 這個開源庫,它實現了Logger缺失的上述特性。
再者,Logger只支持輸出日誌到Logcat,但項目開發中每每還存在將日誌保存到磁盤上的需求,如何將二者結合起來呢?這是就遇到了timber 。
timber是JakeWharton開源的一個日誌記錄庫,它的特色是可擴展的框架,開發者能夠方便快捷的集成不一樣類型的日誌記錄方式,例如,打印日誌到Logcat、打印日誌到文件、打印日誌到網絡等,timber經過一行代碼就能夠同時調用多種方式。
timber的思想很簡單,就是維護一個森林對象,它由不一樣類型的日誌樹組合而成,例如,Logcat記錄樹、文件記錄樹、網絡記錄樹等,森林對象提供對外的接口進行日誌打印。每種類型的樹均可以經過種植操做把本身添加到森林對象中,或者經過移除操做從森林對象中刪除,從而實現該類型日誌記錄的開啓和關閉。
最終咱們的日誌記錄模塊將由timber+Logger+LogUtils組成,固然輪子找到了,輪子的兼容合併就得靠咱們本身實現了,同時咱們還得增長打印到文件的日誌樹和打印到網絡的日誌樹實現。
移動互聯網產品與服務器端通訊的數據格式,若是沒有特殊需求的話,通常都使用JSON格式。Android系統也原生的提供了JSON解析的API,可是它的速度很是慢,並且沒有提供簡潔方便的接口來提升開發者的效率和下降出錯的可能。因此咱們就開始找第三方開源庫來實現JSON解析,比較優秀的包括以下幾種。
gosn是Google出品的JSON解析函數庫,能夠將JSON字符串反序列化對應的Java對象,或者反過來將Java對象序列化爲對應的JSON字符串,免去了開發者手動經過JSONObject和JSONArray將JSON字段逐個進行解析的煩惱,也減小了出錯的可能性,加強了代碼的質量。使用gson解析時,對應的Java實體類無需使用註解進行標記,支持任意複雜Java對象包括沒有源代碼的對象。
jcakson是Java語言的一個流行的JSON函數庫,在Android開發中使用時,主要包含三部分。
因爲jackson是針對Java語言通用的JSON函數庫,並無爲Android優化定製過,所以函數保重包含不少非必要的API,相比其餘的JSON函數庫,用於Android平臺會更顯著的增大最終生成的APK的體積。
Fastjson是阿里巴巴出品的一個Java語言編寫的高性能且功能完善的JSON函數庫。它採用一種「假定有序快速匹配」的算法,把JSON Parse的性能提高到極致,號稱是目前Java語言中最快的JSON庫。Fastjson接口簡單易用,已經被普遍使用在緩存序列化、協議交互、Web輸出、Android客戶端等多種應用場景。
因爲是Java語言通用的,所以,之前在Android上使用時,Fastjson不可避免的引入了不少對於Android而言冗餘的功能,從而增長了包大小,不少人使用的就是標準版的fastjson,但事實上,fastjson還存在一個專門爲Android定製的版本---fastjson.android 。和標準版本相比,Android版本去掉了一些Android虛擬機dalvik不支持的功能,使得jar更小。
LoganSquare是近兩年崛起的快速解析和序列化JSON的Android函數庫,其底層基於jackson的streaming API,使用APT(Android Annotation Tool)實現編譯時註解,從而提升JSON解析和序列化的性能。官網上能夠看到LoganSquare和gson、jackson databind的性能對比。
從性能方面看,LoganSquare是完勝gson和jackson的。若是和fastjson相比較,二者應該是不相上下的。
再來看下jar包的大小
從性能和包大小綜合考慮,最終咱們會選擇Fastjson.android做爲基礎技術堆棧中的JSON解析和序列化庫。
不管是iOS仍是Android,底層數據庫都是基於開源的SQLite實現,而後在系統層封裝成用於應用層的API。雖然直接使用系統的數據庫API性能很高,可是這些API接口並非很方便開發者使用,一不當心就會引入Bug,並且代碼的視覺效果也不佳。爲了解決這個問題,對象關係映射(ORM)框架出現了,比較好的有ActiveAndroid,ormlite和greenDAO。
ActiveAndroid是一種Active Record風格的ORM框架,Active Record(活動目錄)是Yii,Rails等框架中對ORM實現的典型命名方式。它極大的簡化數據庫的使用,使用面向對象的方式管理數據庫,告別手寫SQL的歷史。每個數據庫表均可以被映射爲一個類,開發者只需使用相似save()或者delete()這樣的函數便可。
不過ActiveAndroid已經基本上處於維護階段了,最新的一個Release版本是在2012年發佈的。
ormlite是Java平臺的一個ORM框架,支持JDBC鏈接、Spring和Android平臺。在Android中使用時,它包含兩部分。
與ActiveAndroid相似,ormlite也已經不是一個活躍的開源庫,最近一次Release版本是在2013年發佈的。
greenDAO是一個輕量級且快速的ORM框架,專門爲Android高度優化和定製,它可以支持每秒數千條記錄的CRUD操做。官網上給出一張性能對比圖
縱軸表示每秒執行的操做數。並且greenDAO處在高度活躍中,最新Release版本是在2017年3月份發佈的
Realm是一個全新的移動數據庫引擎,它既不是基於iOS平臺的Core Data,也不是基於SQLite,它擁有本身的數據庫存儲引擎,並實現了高效快速的數據庫構建操做,相比Core Data和SQLite,Realm操做要快不少,跟ORM框架相比就更不用說了。
Realm的好處以下:
咱們看下上述四種數據庫包大小。
能夠看出,前三個仍是正常範圍,但Realm的大小通常項目可能沒法接受。這是由於不一樣CPU架構平臺的 .so 文件增長了整個包的大小,因爲arm平臺的so在其餘平臺上面可以以兼容模式運行的,雖然會損失性能,可是能夠極大地減小函數庫佔用的空間。所以,能夠選擇只保留armeabi-v7a和x86兩個平臺的 .so 文件,直接刪除無用的 .so 文件,或者經過工程的build.gradle文件中增長 ndk abi 過濾,語句以下:
android {
...
defaultConfig {
...
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
}複製代碼
所以,綜合性能考慮,包大小以及開源庫的可持續發展等因素,咱們最終選擇greenDAO。
如今的APP幾乎都須要從服務器獲取數據,不可避免的須要具有網絡通訊的能力,不然就是一個死界面。
Android最經典的網絡異步通訊函數庫,它對Apache的HttpClient API的封裝使得開發者能夠簡潔優雅地實現網絡請求和響應,而且同時支持同步和異步請求。主要特性以下:
可是在6.0以後,系統對開發者隱藏了HttpClient函數庫,這顯著增大了使用android-async-http的代價。 若是鐵了心想繼續使用HttpClient,官方推薦的作法是在編譯期引入org.apache.http.legacy
這個庫,庫目錄在Android SDK目錄下的platforms\android-23\optional中找到,它的做用是確保在編譯時不會出現找不到HttpClient相關API的錯誤,在應用運行時能夠不依賴這個庫,由於6.0以上的Android系統尚未真正移除HttpClient的代碼,只不過API設置爲對開發者不可見。咱們查看android-async-http源碼發現,須要使用下面這個函數庫來替換以前的Apache的HttpClient。
dependencies {
compile 'cz.msebera.android:httpclient:4.3.6'
}複製代碼
這樣顯著的增長了APP的包的大小,若是想繼續使用android-async-http,那麼你的APP須要額外增長1.1MB左右的大小。
OkHttp是一個高效的HTTP客戶端,具備以下特性。
OkHttp在網絡性能不好的狀況下可以很好地工做,它可以避免常見的網絡鏈接問題。若是你的HTTP服務有多個IP地址,OkHttp在第一次鏈接失敗是,會嘗試其餘可選的地址。這對於IPv4+IPv6以及託管在冗餘數據中心的服務來講是必要的。OkHttp使用現代的TLS特性(SNI,ALPN)初始化HTTP鏈接,當握手失敗時,會下降使用TSL1.0初始化鏈接。
OkHttp依賴於okio,okio做爲java.io和java.nio的補充,是square公司開發的一個函數庫。okio使得開發者能夠更好地訪問、存儲和處理數據。一開始是做爲OkHttp的一個組件存在的,固然咱們也能夠單獨使用它。
使用Okhttp須要引入Jar包,包的大小爲:326+66 = 392KB
Volley是Google在2013年發佈的用於Android平臺的網絡通訊庫,能使網絡通訊更快、更簡單、更健壯。官網配出一張弓箭發射圖來講明Volley特別使用於數據量小等通訊頻繁的場景。
具體的將,Volley是爲了簡化網絡任務而設計的,用於幫助開發者處理請求、加載、緩存、多線程、同步等任務。Volley設計了一個靈活的網絡棧適配器,在Android2.2及以前的版本中,Volley底層使用Apache HttpClient,在Android2.3及以上版本中,它使用HttpURLConnection來發起網絡請求,並且開發者也很容易將網絡棧切換成使用OkHttp。
Volley 官方源碼託管在Google Source上面,使用時只能直接以Jar包形式引入,若是想在Gradle中使用compile在線引入,能夠考慮使用mcxiaoke在Github上面的Volley Mirror,而後再build.gradle中使用以下語句便可。
compile 'com.mcxiaoke.volley:library:1.0.19'複製代碼
確切的說,Retrofit並非一個完整的網絡請求函數庫,而是將REST API轉換成Java接口的一個開源函數庫,它要求服務器API接口遵循REST規範。基於註解使得代碼變得很簡潔,Retrofit默認狀況下使用GSON做爲JSON解析器,使用OkHttp實現網絡請求,三者一般配合使用,固然咱們也能夠將這二者換成其餘的函數庫。
經過以上分析,HttpURLConnection、Apache HttpClient 和OkHttp封裝了底層的網絡請求,而android-async-http,Volley和Retrofit是基於前面三者的基礎上二次開發而成。
最後看下函數庫的大小
圖片緩存函數庫有不少很是優秀的,開發人員能夠根據需求進行選擇。傳統的圖片緩存方案中設置有兩級緩存,分別是內存緩存和磁盤緩存。在Facebook推出的Fresco中,它增長了一級緩存,也就是Native緩存,這極大地下降了使用Fresco的APP出現OOM的機率。
BitmapFun函數庫是Android官方教程中的一個圖片加載和緩存實例,對於簡單的圖片加載需求來講,使用BitmapFun就夠了,在早期用的多,如今漸漸退出了實際項目開發的舞臺。
Picasso是著名的square公司衆多開源項目中的一個,它除了實現圖片的下載和二級緩存功能,還解決了常見的一些問題。
在Picasso中,咱們使用一行代碼便可實現圖片下載並渲染到ImageView中。
Picasso.with(context).load(url).into(imageView);複製代碼
Glide是Google推薦的用於Android平臺上的圖片加載和緩存函數庫。這個庫被普遍應用在Google的開源項目中,Glide和Picasso有90%的類似度,只是在細節上仍是存在很多區別。Glide爲包含圖片的滾動列表作了儘量流暢的優化。除了靜態圖片,Glide也支持GIF格式圖片的顯示。Glide提供了靈活的API可讓開發者方便地替換下載圖片所用的網絡函數庫,默認狀況下,它使用HttpUrlConnection做爲網絡請求模塊,開發者也能夠根據本身項目的實際需求靈活使用Google的Volley或者Square的OkHttp等函數庫進行替換。
Glide的使用也可使用一行代碼來完成,語句以下
Glide.with(context).load(url).into(imageView);複製代碼
Fresco是Facebook開源的功能強大的圖片加載和緩存函數庫,相比其餘圖片緩存庫,Fresco最顯著的特色是具備三級緩存:兩級內存緩存和一級磁盤緩存。主要特性以下:
Android-Universal-Image-Loader簡稱UIL,是Android平臺老牌的圖片下載和緩存函數庫,功能強大靈活且高度可自定義,它提供一系列配置選項,並能很好地控制圖片加載和緩存的過程。使用者甚多,如今項目仍在使用。UIL也支持二級緩存,特性以下:
最後看下幾個庫的包大小
圖片函數庫的選擇須要根據APP的具體狀況而定,對於嚴重依賴圖片緩存的APP,例如壁紙類,圖片社交類APP來講,能夠選擇最專業的Fresco。對於通常的APP,選擇Fresco會顯得比較重,畢竟Fresco 3.4MB的體量擺在這。
根據APP對圖片顯示和緩存的需求從低到高咱們能夠對以上函數庫作一個排序
BitmapFun < Picasso < Android-Universal-Image-Loader < Glide < Fresco複製代碼
值得一提的是,若是你的APP計劃使用React Native進行部分模塊功能的開發的話,那麼在基礎函數庫選擇方面須要考慮和React Native的依賴庫的複用,這樣能夠減小引入React Native 所增長的APP的大小,能夠複用的函數庫有:OkHttp,Fresco,jackson-core.
《Android高級進階》顧浩鑫