1. 程式人生 > >IT觀察】網路通訊、圖片顯示、資料庫操作……Android程式設計師如何利用開源框架

IT觀察】網路通訊、圖片顯示、資料庫操作……Android程式設計師如何利用開源框架


【51CTO.com原創稿件】每個Android 程式設計師都不是Android應用開發之路上孤軍奮戰的一個人,GitHub上浩如煙海的開源框架或類庫就是前人為我們發明的輪子,有的輪子能提高軟體效能,而有的輪子似乎是以犧牲效能為代價換取程式設計速度。擅長利用輪子的程式設計師已經遙遙領先,不擅長利用輪子的程式設計師總是嫌前人發明的輪子不夠圓,自己造個方輪子上路後才發現落後了。

輪子

技術選型的考量點

來自不同行業、面向不同使用者的App對功能特性、各方面效能的要求都是不同的,選擇開源框架和類庫不能掉以輕心,我們在選擇開源框架之前務必要選擇幾個考量點進行技術選型。我們選擇開源框架可以從以下三個方面考慮(排名有先後):

1、功能特性:提供的特性是否滿足專案的需求。比如Picasso不支援GIF圖和視訊縮圖等,不適合視訊應用。

2、程式設計效率:是否有預設引數,配置是否複雜。是否可以一鍵呼叫,不需要二次封裝。API是否簡潔易懂,可以望文生義。僅在module的build.gradle裡依賴和還需要在project的build.gradle裡依賴對程式設計師細心程度的要求是不一樣的,並且需要開發者配置引數的UIL被Picasso取代也不足為奇。

3、效能:處理速度不能太慢,穩定性也不能太差,佔用記憶體不應該太高,jar的體積可以不能太大。此外過大的jar包一定包含過多的方法數,積累起來會導致你的APP遇到64K問題。Fresco的體積就太大了點。

我為什麼要把程式設計效率排在效能之前,因為程式設計師的工資每年都在上漲,經常出現薪資倒掛現象,而同等價格的Android裝置的效能每18個月翻一番。再舉一個極端的例子:“實現“3的3次方”有三種寫法:

“3^3”、“3*3*3”、“(3+3+3)+(3+3+3)+(3+3+3)”,顯然正常人都會用第一種方法,但第三種方法的效能才是最好的。

確定了技術選型的考量點以後,我們接下來要確定最常用的六大類開源框架的選型:

一、網路通訊

Android程式設計師都是移動網際網路開發者,很少有不依賴網路的App,網路許可權幾乎是每個App必然要申請的許可權,網路通訊框架的選擇也是一個App專案中技術選型的最重要組成部分。

android-async-http

android-async-http是Android最經典的網路非同步通訊框架,它對Apache的HttpClient API的封裝使得開發者可以簡潔優雅地實現網路請求和響應。因為Android 6.0以後去掉了HttpClient,這就敲響了android-async-http的喪鐘,目前已經很少有人使用這個框架。

OkHttp

OkHttp是Square出品的一個簡潔、快速、高效的HTTP客戶端,支援HTTP/2以及SPDY,扮演著傳輸層的角色。它既能在網路效能很差的情況下很好地工作,也能夠避免常見的網路連線問題。OkHttp的常規用法:

  1. OkHttpClient okHttpClient = new OkHttpClient(); 
  2. Request request = new Request.Builder() 
  3.         .url("http://短連線") 
  4.         .build(); 
  5. Call call = okHttpClient.newCall(request); 
  6. call.enqueue(new Callback() { 
  7.     @Override 
  8.     public void onFailure(Call call, IOException e) { 
  9.         e.printStackTrace(); 
  10.     } 
  11.     @Override 
  12.     public void onResponse(Call call 
  13.             , Response response) throws IOException { 
  14.     } 
  15. }); 

儘管名字帶有“Http”,但OkHttp的功能並不侷限於http請求。以前的版本可以通過外掛來實現WebSocket長連線,而3.5以後的版本則直接支援WebSocket:

  1. OkHttpClient client = new OkHttpClient 
  2.         .Builder() 
  3.         .readTimeout(0,  
  4.                 TimeUnit.MILLISECONDS) 
  5.         .build(); 
  6. Request request = new Request 
  7.         .Builder() 
  8.         .url("ws://ws打頭的連結就是長連線") 
  9.         .build(); 
  10. WebSocket webSocket = client 
  11.         .newWebSocket(request, new WebSocketListener() { 
  12.     @Override 
  13.     public void onMessage(WebSocket webSocket, String text) { 
  14.         super.onMessage(webSocket, text); 
  15.     } 
  16.     @Override 
  17.     public void onFailure(WebSocket webSocket,  
  18.                           Throwable t, Response response) { 
  19.         super.onFailure(webSocket, t, response); 
  20.     } 
  21. }); 

Volley

Volley是Google開發的一個簡化網路任務的庫。Volley側重於Request的佇列的管理,適合請求、載入、快取、多執行緒、同步等各類任務,尤其能使資料量小但通訊頻繁的場景中的網路通訊更快、更簡單、更健壯。Volley的常規用法:

  1. StringRequest stringRequest = new StringRequest(Request.Method.GET 
  2.         ,"http://普通Volley" 
  3.         , new Response.Listener<String>() { 
  4.             @Override 
  5.             public void onResponse(String response) { 
  6.             } 
  7.         }, new Response.ErrorListener() { 
  8.     @Override 
  9.     public void onErrorResponse(VolleyError error) { 
  10.         error.printStackTrace(); 
  11.     } 
  12. }); 
  13. Volley.newRequestQueue(this).add(stringRequest); 

Volley在頻繁訪問伺服器有很大的優勢,OkHttp在效能、速度方面優勢明顯一,點。我們可以用OkHttp來擴充套件Volley,這樣能讓二者取長補短。

Retrofit

Retrofit並不是一個單純的網路請求函式框架,而是能直接請求得到實體類的整套組合框架。Retrofit預設使用Gson作為JSON解析器,預設使用OkHttp實現網路請求,同時基於註解使得程式碼變得非常簡潔,當然我們也可以將OkHttp和Gson換成其他的函式庫。

【小結】我個人不建議使用有點過度封裝的Retrofit,尤其當一個App的團隊業務較複雜或人員變動太頻繁而導致域名字首、header、contentType等變化太多時。資料量小但通訊頻繁的App,例如有輪詢等功能的時候適合用Volley,而中等以上體量的App則適合用OkHttp,但我更建議把OkHttp和Volley結合在一起使用。

二、圖片快取與顯示

圖片歷來是Android手機中的吃記憶體大戶,稍不留意就會出現OOM,所以能否做好圖片的快取是一個App效能好壞的決定性指標,對圖片快取與顯示框架的技術選型不得不重視。

Universal-Image-Loader

Universal-Image-Loader(以下簡稱UIL)是Android平臺老牌的圖片快取與顯示框架,也是大多數3年以上的Android程式設計師入行以來接觸的第一個框架。功能強大靈活且高度可自定義,因此在Picasso流行開來之前一直是最流行的Android圖片載入庫,目前仍有大量開發者使用。

Picasso

Picasso是著名的Square公司眾多開源專案中的一個,最顯著的優點就是體積非常輕小,僅有120KB,也因此常常成為眾多深入研讀原始碼的程式設計師第一個研讀的框架。

  1. Picasso.with(this) 
  2.         .load("圖片地址:url或path") 
  3.         .placeholder(R.mipmap.ic_launcher) 
  4.         .error(R.mipmap.ic_launcher) 
  5.         .resize(100,100) 
  6.         .centerCrop() 
  7.         .centerInside() 
  8.         .into(imageView); 

Glide

Glide是Google官方推薦的用於Android平臺上的圖片載入和快取庫,被廣泛應用在Google的開源專案中。Glide除了為包含圖片的滾動列表()做了儘可能流暢的優化外,還支援GIF格式圖片以及視訊縮圖的顯示。

  1. Glide.with(this) 
  2.         .load("圖片地址:url或path") 
  3.         .placeholder(R.mipmap.ic_launcher) 
  4.         .error(R.mipmap.ic_launcher) 
  5.         .override(100,100)//此處與Picasso不同 
  6.         .centerCrop() 
  7.         .fitCenter()//此處與Picasso不同 
  8.         .into(imageView); 

可見Glide和Picasso有90%的相似度,只是在細節上還是存在不少區別。

Glide提供了靈活的API可以讓開發者方便地替換下載圖片所用的網路函式庫,預設情況下,它使用HttpUrlConnection作為網路請求模組,開發者也可以根據自己專案的實際需求靈活使用Google的Volley或者Square的OkHttp等函式庫進行替換。

Fresco

Fresco是Facebook開源的功能強大的圖片快取與顯示框架。圖片快取方案一般有兩級快取,分別是記憶體快取和磁碟快取。目前最流行的“三級快取”說法是錯誤的,所謂“網路快取”並不是Android端所控制的。在Fresco中增加了一級記憶體快取,這使得Fresco成了載入大量大圖之後OOM概率最低的圖片快取與顯示框架。

Fresco無與倫比的載入速度和穩定性讓它在2015年流行過一陣子,但強大的效能是以增加App 3.4M的體積換來的,並且Fresco使用有些複雜,導致了Fresco只適合大型App;而Picasso的功能太少,僅適用於小型App;綜上,一般體量和功能的App建議選擇Glide。

我們不要拘泥於用開源框架或自定義控制元件載入圖片,在電商類應用中常見的類似淘寶詳情頁的那種很長很長的圖片的url,建議直接用WebView顯示:

  1. webView.loadUrl("淘寶或微博長長的圖"); 
  2. WebSettings webSettings = webView.getSettings(); 
  3. webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); 
  4. webSettings.setJavaScriptEnabled(true); 
  5. webView.setWebViewClient(new WebViewClient() { 
  6.     @Override 
  7.     public void onPageFinished(WebView view, String url) { 
  8.         super.onPageFinished(view, url); 
  9.         String javascript = "javascript:function ResizeImages() {" + 
  10.                 "var myimg,oldwidth;" + 
  11.                 "var maxwidth = document.body.clientWidth;" + 
  12.                 "for(i=0;i <document.images.length;i++){" + 
  13.                 "myimg = document.images[i];" + 
  14.                 "if(myimg.width > maxwidth){" + 
  15.                 "oldwidth = myimg.width;" + 
  16.                 "myimg.width = maxwidth;" + 
  17.                 "}" + 
  18.                 "}" + 
  19.                 "}"; 
  20.         view.loadUrl(javascript); 
  21.         view.loadUrl("javascript:ResizeImages();"); 
  22.     } 
  23. }); 

三、資料庫操作

Android的資料庫是基於開源的SQLite實現的,適用於儲存大量資料,不過和上文的JavaScript程式碼一樣,SQL程式碼也是用String形式的,所以IDE沒有自動糾錯和程式碼補全功能,這就意味著我們需要一個不用寫複雜的sql語句,而用簡單的API即可完成建立和操縱資料的資料庫操作框架。

ORMLite

ORMLite是目前使用人數最多的資料庫操作框架,儘管在2013就已經停止維護,但因為操作簡便仍然廣受歡迎。

SugarORM

SugarORM是一個較冷門的資料庫操作框架,效能暫且不論,單憑每次增加列必須在assests裡新建一個SQL檔案就夠讓人頭疼了。

GreenDAO

GreenDAO是一個輕量級且快速的ORM框架,專門為Android高度優化和定製,它能夠支援每秒數千條記錄的CRUD操作。儘管讀寫速度是ORMLite的4倍,但複雜的學習過程和操作方式卻令人望而卻步。

Realm

Realm並不是一個基於SQLite的資料庫框架,而是一個自有資料庫引擎,並且帶有資料庫視覺化操作工具的整套資料庫操作解決方案。

Realm有一個顯著的優點是跨平臺,Android和iOS開發者無需考慮內部資料的架構,呼叫Realm提供的API即可輕鬆完成資料的交換。其次Realm為開發者提供了一個輕量級的資料庫視覺化操作工具,保證了開發者可以輕鬆檢視資料庫中的內容,並實現簡單地插入和刪除等操作。

Realm的速度也比其他框架快得多,不過Realm的體積高達4.2MB,一般專案可能無法接受。

【小結】綜合性能考慮,包大小以及開源庫的可持續發展等因素,建議對資料庫要求較高的 App採用GreenDAO,對資料要求極其嚴格的App採用Realm,而一般的App採用ORMLite,畢竟程式設計效率才是王道。

四、JSON解析與生成

移動網際網路產品與伺服器端通訊的資料格式,如果沒有特殊需求的話,一般都使用JSON格式。Android系統也原生的提供了JSON解析的API,但是速度非常慢,而且沒有提供簡潔方便的介面來提高開發者的效率和降低出錯的可能。

Gson

Gosn是Google出品的JSON解析函式庫,可以將JSON字串反序列化對應的Java物件,或者反過來將Java物件序列化為對應的JSON字串,免去了開發者手動通過JSONObject和JSONArray將JSON欄位逐個進行解析的煩惱,也減少了出錯的可能性,增強了程式碼的質量。使用Gson解析時,對應的Java實體類無需使用註解進行標記,支援任意複雜Java物件包括沒有原始碼的物件。

  1. GsonPlayer gsonPlayer = new Gson() 
  2.         .fromJson("{\"age\":0,\"name\":\"姓名\"}" 
  3.                 ,GsonPlayer.class); 

上文提到的資料庫框架適合儲存大量資料,而儲存少量資料時則可以用SharedPreferences儲存JSON的形式:

  1. List list = new ArrayList(); 
  2. for (int i=0;i<10;i++){ 
  3.     Map map = new HashMap(); 
  4.     map.put("age",i); 
  5.     map.put("name",""+i); 
  6.     list.add(map); 
  7. String JSON = new Gson().toJson(list); 

Jackson

Jackson是Java語言的一個流行的JSON函式庫,並沒有為Android優化定製過,因此函式保重包含很多非必要的API,用於Android平臺會更顯著的增大最終生成的APK的體積。

Fastjson

Fastjson是阿里巴巴出品的一個Java語言編寫的高效能且功能完善的JSON函式庫。它採用一種“假定有序快速匹配”的演算法,號稱是目前Java語言中最快的JSON庫。Fastjson還存在一個專門為Android定製的版本,和標準版本相比,Android版本去掉了一些Dalvik不支援的功能,使得jar包更小。

  1. FastjsonPlayer fastjsonPlayer  = JSON 
  2.         .parseObject("{\"age\":0,\"name\":\"姓名\"}" 
  3.                 ,FastjsonPlayer.class); 

【小結】在解析長JSON時Fastjson有明顯的速度優勢,但解析普通長度的JSON時Gson卻略勝一籌。從速度、體積、文件和技術支援、官方推薦等方面綜合考慮,Gson毫無疑問是最佳選擇。

五、元件間通訊

Android中Activity、Service、Fragment等元件以及不同程序之間的相互通訊主要有Broadcast和Handler兩種方法,但這些方法都比較繁瑣。事件匯流排是一種比較簡便的方法,其基本原理是傳送者把訊息傳送到事件匯流排,然後事件匯流排在接收者中查詢哪些方法註冊了這個事件,如果某個方法註冊了這個事件,就觸發該方法。

EventBus

EventBus是專為一個Android端優化的publish/subscribe訊息匯流排,簡化了應用程式內各元件間、元件與後臺執行緒間的通訊。用事件匯流排原理實現元件間通訊可能會造成效能問題:EventBus在釋出Event的時候就要做好準備可能並沒有人接受這個Event, Subscribe的時候也要做好準備可能永遠不會收到Event。Event無論順序還是時間上都某種程度上不太可控。我們可以利用響應式程式設計來解決這個問題。

RxJava

RxJava是一個在 JVM 上使用可觀測的序列來組成非同步的、基於事件的程式的響應式程式設計框架。如果一個訂閱者需要註冊多個事件的時候,Rxjava需要一個個單獨的註冊,而EventBus則可以實現一個訂閱者訂閱多個事件,和一個事件對應多個訂閱者。顯然RxJava的效能更好,但EventBus操作更簡便。

【小結】元件間通訊框架還有Otto和Guava等許多種,但都在某些方面稍有欠缺,因此我們技術選型的範圍就在EventBus和RxJava之間,建議小型App選擇EventBus,體量中等以上的App選擇RxJava或RxAndroid。

六、依賴注入

所謂依賴注入,就是目標類(目標類需要進行依賴初始化的類(JavaBean))中所依賴的其他的類的初始化過程,不是通過手動編碼的方式建立(findViewById等),而是通過技術手段(註解和反射等)可以把其他的類的已經初始化好的例項自動注入到目標類中。

AndroidAnnotations

AndroidAnnotations是功能最豐富的依賴注入框架,但存在體積過於龐大、與其他利用註解的框架有衝突、輸出太多logcat、需要生成一個以“_”結尾的新類都是與追求程式設計效率的初衷相違背的。

ButterKnife

ButterKnife具備AndroidAnnotations的大多數主要功能,並且使用簡便,這是ButterKnife在Activity中的使用:

  1. public class ButterKnifeActivity extends AppCompatActivity { 
  2.     private Unbinder unbinder; 
  3.     @BindString(R.string.str_butter_knife) 
  4.     String butterKnifeStr; 
  5.     @BindDrawable(R.mipmap.ic_launcher) 
  6.     Drawable butterKnifeDrawable; 
  7.     @BindView(R.id.iv_butter_knife) 
  8.     ImageView butterKnifeIv; 
  9.     @Override 
  10.     protected void onCreate(Bundle savedInstanceState) { 
  11.         super.onCreate(savedInstanceState); 
  12.         setContentView(R.layout.activity_butter_knife); 
  13.         unbinder = ButterKnife.bind(this); 
  14.         butterKnifeIv.setImageDrawable(butterKnifeDrawable); 
  15.     } 
  16.     @OnClick(R.id.btn_butter_knife) 
  17.     public void onButterKnifeBtnClick(View view) { 
  18.         Toast.makeText(this,butterKnifeStr,Toast.LENGTH_SHORT).show(); 
  19.     } 
  20.     @Override 
  21.     protected void onDestroy() { 
  22.         super.onDestroy(); 
  23.         unbinder.unbind(); 
  24.     } 

ButterKnife能增強程式碼的可讀性,提高程式設計效率,但如果你用Android Studio搜尋Android ButterKnife Zelezny外掛後,你會發現寫以上程式碼也是浪費時間之舉,因為這些都能自動實現。

【小結】AndroidAnnotations和ButterKnife都是犧牲執行效能換取開發速度的工具,體積龐大的AndroidAnnotations對compile速度較大,而ButterKnife對runtime效能的影響略大於AndroidAnnotations。綜合考慮之後,為了寫出更高質量的程式碼,也為了debug更簡便,我選擇了ButterKnife。

【寫在最後】

上述Android開源框架的合理利用能加快開發進度,也能提高程式碼可維護性。除了上述幾大框架,Android開源框架還有多媒體、檔案I/O、動畫等多個大類,合理運用開源框架提高程式設計效率節省下來的時間可以用於讀書、健身或陪陪自己的另一半,早日成為人生贏家。

歡迎掃碼加群學習

51CTO開發者交流群④群 627843829

【51CTO原創稿件,合作站點轉載請註明原文作者和出處為51CTO.com】

相關推薦

no