隨着環境問題愈來愈嚴重,人們愈來愈重視低碳環保的生活方式。做爲碼農的咱們天然也應該爲環保作出應有的貢獻。那麼什麼是低碳環保,簡而言之就是就是低能量、低消耗、低開支的生活方式,映射到咱們的工做中就是以最低的消耗的來完成組織交給咱們的任務。html
如下就以 Android 開發爲例從庫和語言兩方面來討論如何實現低碳環保的編程方式。java
充分利用現存資源,儘量不重複造輪子。從以往來看,若是你對現存的輪子有各類不滿試圖從頭寫,那麼最終結局中可能性最大的就是隻寫了部分後直接放棄轉而成爲某個輪子的支持者,寫完且比現有輪子要好的可能性還不如轉行去大學城門口賣炒麪。固然若是你寫的是就是 SDK 之類的基礎工具,那仍是儘可能減小依賴爲好。android
那麼該如何挑選第三方庫呢?Android 的應用層開發雖然使用 Java 語言,但並非 Java 上的庫都適合 Android 開發。Android 使用的不是 Oracle JDK 也不是 Open JDK,而是 Google 改寫過的 Apache Harmony JDK,不少 Oracle JDK 自帶的類(特別是 javax 包下的)在 Android 中並不存在,因此使用這些方法的庫 Android 不能使用。git
此外 Android 存在 65536 問題,這個坑體如今如下兩點:程序員
1)Android 機器在應用的安裝過程當中,系統會運行 dexopt
工具,將 .dex
文件優化爲 .odex
文件,其中 dexopt
工具使用了固定的緩衝區大小來保存方法的元信息,低版本的 Android 機器上該緩衝區很是小,因此一旦方法數過多會直接致使 dexopt
崩潰,應用沒法運行。github
2)Dalvik 指令集對於一個 .dex
文件只能保存 65536 個方法的索引,因此一個 .dex
文件即便能夠擁有不少方法,可是那些多餘的方法也都是沒法運行的。詳細信息能夠閱讀官方的 dalvik-bytecode 的 invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB
條目。mongodb
所以選擇 Android 的第三庫須要嚴格注意控制方法的總數量。編程
如下我總結了一些 J2EE 和 Android 上的經常使用庫的對比以供參考,使用這些庫能夠有效提供編程效率,減小能量消耗:swift
功能 | J2EE | Android | 備註 |
---|---|---|---|
JSON 解析 | Jackson | Gson | Jackson 功能全面,但太大;Gson 速度通常但勝在體積 |
Restful | Jersey | Retrofit | Jersey 面向服務端,符合 JAX-RS 標準, Retrofit 面向客戶端,不符合 JAX-RS 標準 |
依賴注入 | Guice | Dagger | Guice 使用反射,Dagger 使用預編譯,效率不是一個等級的 |
NoSQL | MongoDB | Realm | Realm 兼容 Android,iOS,ReactNative,比起 Sqlite3 快得多 |
單元測試 | JUnit | Robolectric + Espresso | JUnit 只能運行在 JVM 上,Robolectric 使 Android 代碼能夠運行在 JVM 上,Espresso 簡化 UI 測試流程(雖然不少狀況下 UI 測試沒什麼用) |
異步調用 | CompletableFuture/RxJava | RxJava + RxAndroid + RxLifecycle | 三合一基本是標配,除此以外還能夠加上 RxBinding,RxPermissions,RxAndroidAudio 等等組成完整的 Rx 你們族 |
網絡請求 | - | OkHttp/Volley | OkHttp 功能強大,Fluent API 能夠寫出更優秀的代碼;Volley 代碼量小容易擴展,有很是優秀的隊列機制 |
時間處理 | Java 8/Joda-Time | - | Java 原生時間處理 API 很是糟糕,所以 Java 8 直接加入了 Joda-Time。Joda-Time 雖然易用,但一個只是處理時間的庫有 5000 多方法對於 Android 顯然不實際,儘管有 joda-time-android 庫但一般 Android 端須要處理時間代碼很少,建議仍是直接調用難用的原生 API |
構建良好的 Android 架構,儘可能將 Context 相關的一切和業務邏輯進行分離,使業務邏輯可以脫離於 UI 組件進行本地測試。MVC,MVP,MVVM,Flux 之類的只有適合本身才是最好的。也能夠參考下 Google 最近開始編寫的 Android 架構的示例代碼,不得不說 Google 這一步作得是實在有點晚。後端
引入 Fragment 後 Android 應用的生命週期 過於恐怖,因此儘管 Google 提倡使用 Fragment,但仍是能少用就儘可能少用。
使用 Timber + Hugo 記錄 Log 信息而不是使用原生的 Log 工具,這樣無需再本身拼接類名,方法名,參數名和參數值,也不用爲了使 Log 更容易被識別加上一堆 =========afafaf=============
或者 ~~~~~~~~~~~~~~~~~~~~~
這樣的提示符。
使用 Android DataBinding,儘管你不必定喜歡它的數據綁定方式。可是使用了 DataBinding 後你無需調用 findViewById
後再強制進行類型轉換,也不用使用 Butter Knife 之類的庫編寫各類註解。
對於圖像加載注重質量和包大小可使用 Picasso,注重加載速度或者須要支持 GIF 類型和大圖片可使用 Google 人出品的 Glide。除此以外還有老牌的 Universal Image Loader 和相對較新的 Facebook 出品的 Fresco(Fresco 在這裏面是重量級選手,不管是功能仍是體積,剛推出時坑很多,還有很是嚴重的內存泄露,目前該庫已經做爲 React Native 的圖片加載庫,不知道這些問題都解決了麼)
使用 IDEA Live Template 保存經常使用的類或方法的模板,這是我最常使用的方式,這樣有時甚至能夠減小近一半的工做量。
強制豎屏,Android 上除了視頻播放和遊戲大部分狀況下豎屏足以,根據 2-8 法則不少時候專門適配橫屏是很大的資源浪費
以上的方法在實現低碳環保的功能上仍是很是有限的,因此還有種方法就是直接從最根本的語言層面進行着手。
使用 Lambda 表達式能夠省去很多代碼,惋惜直到 Java 8 才支持,索性的是 Android 上有一些解決方法。
Retrolambda Gradle 插件能夠在編譯時經過字節碼轉換使 Android 可以使用 Lambda 表達式。
在介紹 Jack 與 Jill 以前先來看看 Android 那坑爹的構建系統,如下圖片來自 Google 官方文檔,請注意這只是一個大綱,並且有些過期,實際更復雜,想一想若是沒有 IDE 本身手動敲的痛苦吧:
而 Jack 與 Jill 就是在 Android M 時 Google 爲了簡化以上流程而推出的構建工具。
之前的主要流程
爲了減少 I/O 讀取的次數,dx 工具將全部 .class
文件合併成 .dex
文件
javac (.java --> .class) --> dx (.class --> .dex)
使用 Jack 與 Jill
Jill 將第三方 .class
文件和 .jar
文件轉換爲 .jayce
文件。
Jack 將 .java
和 .jayce
文件合併後轉換爲優化過的 .dex
文件。
Jack (.java --> .jack --> .dex) Jill (.class --> .jayce)
固然 Jack 實際是一個工具鏈,除了以上功能 Jack 還包含了 multidex, proguard 等大量功能,直接替代了原來構建過程當中的不少工具。
使用 Jack 與 Jill 還有一個吸引人的特色是能夠在今年將發佈的 Android N 平臺使用上大部分 Java 8 的功能。感興趣的人能夠如今就去嘗試一下,可是須要注意的是 IDE 必須大於 Android Studio 2.1 (preview),SDK 平臺必須爲 Android N Preview SDK。
此外因爲 Java 8 提供的 Lambda 表達式實際就是經過函數式接口實現的,因此在使用 Jack 與 Jill 後這一功能也能夠直接使用在 Android N 之前的平臺,而不用使用 Retrolambda 這些第三方工具(固然其它的 Java 8 功能都不支持)
目前來講 Jack 與 Jill 有一個很大的缺點就是速度較慢,不支持 Instant Run。此外因爲不生成中間狀態的字節碼文件,因此開啓 Jack 與 Jill 後基於字節碼的各類工具(如 JaCoCo, Mockito)都將沒法使用。(注:Gradle 插件在 1.5 版本提供了 Transform API,可讓咱們直接對生成的 dex 文件進行處理,可是目前 Jack 與 Jill 不支持,因此使用該種方式 JaCoCo 仍然沒法使用)
相比較 Lambda 表達式也許換種語言是種更有效的方法。如下就介紹一下適用於 Android 開發的其它語言,固然這並非說真的須要在實際工做中應用。更多得是由於若是你只會用錘子,那你眼裏的全部東西都是釘子,換種語言是爲了開拓思路,瞭解在其它語言中是如何實現一樣的功能的。
該方案以 Java 代碼爲主,以少許 Native 代碼爲輔。主要有兩種實現方式:
Java + C/C++
很明顯這種方法很是不環保,基於 NDK 的開發很是複雜,出了錯誤也很差調試,目前這種方式主要用於 Cocos2D-X 這種遊戲引擎。
Java + Go
Go 從 1.5 版本開始同時支持 Android 和 iOS 開發。因爲 Go 是 Google 親兒子因此 1.5 出來時你們對將來都很是期待。不過至今爲止實際發展很是緩慢,文檔很是稀少。相比較使用 C/C++ 方式使用 Go 有這麼幾個特色:
優勢:
語法簡單,開發迅速,不用寫頭文件,不用寫 Makefile,不用手動寫 Native 方法,藉助插件 Go 代碼會被直接編譯成包含 .so
文件的 .aar
庫,導入 Android 工程後就像寫原生 Java 代碼同樣直接使用便可。
缺點:
文檔奇缺,發展緩慢劇。
目前只支持 arm 架構。
有 Bug,我寫的代碼編譯版本選擇 API 22 正常運行,選擇 API 23 上直接奔潰。
該方案以 Native 代碼爲主,以少許 Java 代碼爲輔。最大的特色就是提倡以同一種語言爲不一樣平臺編寫不一樣代碼,而不是一套代碼處處運行。主要表明有如下幾種:
RubyMotion
RubyMotion 由 MacRuby 的開發者發明,能夠經過 Ruby 代碼編寫 iOS 和 Android 代碼。
優勢:
提供了 Android 上的幾乎全部的 API 的 Ruby 實現,也能夠直接使用 Java 庫。
缺點:
iOS 還有些文檔,Android 方面則沒有任何像樣的官方文檔。致使我在寫的時候須要打開 IDEA 先用 Java 寫一遍大體框架而後再用 Ruby 進行改寫。
不支持直接調用 Java 代碼,必須使用打包好後的 Java 庫。
除了官方發佈的包,不支持其它任何 Gem 上的包。
因爲沒有錢付正式版,因此我使用的是試用版,使用時不但難以調試,速度慢,並且還 Bug 滿天飛,徹底沒有寫 Ruby 的爽快感,正式版估計會好點。
ReactNative
ReactNative 由 Facebook 在去年發佈,一經發布瞬間成爲 Github 上的網紅。可使用 JavaScript 進行代碼的編寫以及動態更新是其最大特色。然而相比較 iOS 來講 Android 版本並無發佈多少時間,目前還有很多問題。因爲最近在看 ReactNative 因此這裏寫得稍微詳細點:
優勢:
使用 JavaScript 編寫,ES 6 語法對於 Java 程序員可能更有親和力。
Flex 佈局和 JSX 語法和 Android 原生布局方式很是相近,不少屬性幾乎就是換個名字,容易上手。
支持 HotLoad,寫個界面刷一下就好了,Android 開發者終於不用忍受 Gradle 那漫長的編譯過程。
缺點:
目前只是 0.2x 版本,不穩定,而且 React Native 自己使用了很多已經標示爲廢棄的 API, API 有很大可能會大更新。
若是碰到框架自己 Bug,基本沒有修復的可能性,只能被動等待官方出解決方案或者切換爲 Java 平臺。
原生 Android 開發就有各類兼容性問題,特別是對於國內小米,華爲,魅族等平臺,國外的 React Native 是否能處理得好不得而知。
ReactNative 框架自身綁定了很多第三方庫,雖然這些庫都挺有名的,但也不能保證人人喜歡,人人用獲得。
沒有重用機制,致使 ListView 效率問題。
沒有佈局管理器,組件間嵌套嚴重,實際代碼中會有大量 <View>
嵌套 <View>
的狀況,不適合寫複雜的佈局。
Android 有多種類型 Resource 文件,還有 10 多種限定修飾符,React Native 基本都沒法使用,意味着在面對屏幕適配,i18n,切換主題等問題時會很是蛋疼。
目前只支持老式的 Drawable 目錄下的圖片資源,不支持 5.0 之後的 Mipmap 目錄下的資源。
Flux 和在其基礎上的 Redux 架構與 Android 傳統開發理念不符,很難吸引到廣大碼農。
相比較以上方案,使用其它 JVM 語言的最大特色就是能夠和 Java 進行無縫切換,開發方式上沒有什麼變動,很容易讓人接受。
Groovy 官方從 2.4 開始就支持了 Android 開發。Groovy 自己是動態語言,效率較低。可是能夠經過開啓靜態編譯來提升效率。因爲 Groovy 在處理 XML 方面是一絕,因此若是你的應用服務器是基於 SOAP 的話,那麼使用 Groovy 替換 Java 無疑是更好的選擇,原生的 DOM,SAX,PULL 方式使用起來都太痛苦了。
替換成 Groovy 後最大的優勢就是上手沒有任何什麼難度, 畢竟全部 Android 開發者都寫過 Groovy (build.gradle
實際就是 Groovy 源文件),而缺點就是編譯速度會更慢。
Android 應用中經常須要將上下文傳來傳去,因此不少人都會在每一個 Activity 寫上 mContext = this
這樣沒養分的代碼。而使用了 Scala 後藉助隱式參數 + 隱式轉換 + 隱式類這三兄弟就不用寫這些沒有養分的代碼。除此以外借助 Scala 各類 FP 特性代碼量也能夠獲得大量減小。
可是替換成 Scala 後有一個致命的弱點就是主流的 Scala 的 2.11.x 版本核心方法多達 5w。這意味着加上 Android 的原生代碼,即便你一行代碼沒寫,僅僅是集成 Scala 運行環境後就超過了 65536 的限制。即便開啓了 proguard 刪除掉那些不用的代碼這個問題也沒辦法根本解決,因此或許將 Scala 搬到 Android 平臺並非一個好的解決方案。
Kotlin 是 JetBrain 研發的一門運行在 JVM 上的語言,官方支持 Android 開發,語法和其以後發佈的 Swift 很是類似,因此也有人開發出了 Kotlin 2Swift 的工具,詳細對比能夠見Swift is like Kotlin。Kotlin 的語法能夠看作是 Scala++--,其語法借鑑了 Scala,可是也去除了 Scala 中大量複雜的概念。
在全部 JVM 語言中,目前我的最推薦使用 Kotlin 進行 Android 開發。有如下幾個緣由:
Kotlin 由 JetBrain 開發,因此對 Android Studio 有很好的支持。
Android 界舉足輕重的 Jake Wharton 大神和其所在的公司 Square 都很欣賞 Kotlin,將一些 Android 庫改寫爲了 Kotlin 版本。
Google Android 項目組也對 Kotlin 感興趣,目前咱們常使用的 Databinding 的編譯器就是 Kotlin 寫的。
Kotlin 的運行庫只有不到 7000 個方法,這意味着它比 v4 還要小。
Google 目前和 Oracle 的官司越演越烈,之前有傳言 Google 會使用 Go 做爲 Android 的一類語言,可是目前從發展速度來看可能性很小。近日又有傳言 Google 會使用 Swift 來代替 Java,我的以爲相比較而言不如說 Kotlin 可能性更大。(補:寫完這段不久後 Swift 就倉庫就出現了 For Android 的 Pull Request,看了下這玩意是基於 JNI 的,屬於上面說的 Java + Native 的開發方式,對於編寫應用來講用處不大,不過相信會被很多人炒做一段時間)
Kotlin 學習 Clojure 也分爲 Kotlin on JVM 和 Kotlin on JavaScript 兩個版本。其中 Kotlin on JavaScript 目前內置了 JQuery,可是自己功能很弱,只能寫些原始的 JS 代碼。若是發展起來的話,說不定未來能夠用於編寫 ReactNative 代碼。
Kotlin 沒有什麼歷史負擔,增長新特性時無需像 Java 同樣思考再三。如下爲 Kotlin 目前的 RoadMap,能夠看到諸如協程之類的功能 Kotlin 都會在語言層面實現,而不用像 Java 同樣必須依賴 Quasar 這種第三方庫在字節碼方面作文章才行。若是等 Java 實現的話搞很差須要等到 Java 20.
就我我的開發中常使用的 Kotlin 功能有這麼幾種:
方法擴展,該功能能夠給已存在的類添加方法,本質上其實現相似 Scala 中的隱式類。因此你能夠直接給 Activity 添加 toast, alert 功能。
使用 DSL 語句來編寫界面
internal 訪問權限。咱們知道 Java 中包與包是沒有任何關係的,這意味這 a.b 和 a.b.c 實際是兩個包。因此在分層時 a.b.c 中不得不暴露大量的 public 方法給 a.b 包中所在的類。而在 SDK 開發中爲了有良好的封裝性,儘可能暴露更少的接口,因此每每不得不將大部分類都放在同一個包中,而後經過 default 訪問權限來限制外部訪問。類少的時候還可以忍受,類的一多的話就會很是混亂。Kotlin 中的 internal 訪問權限能夠限制只能屬於同一個模塊中的類進行訪問,其它模塊沒法訪問。那麼什麼是模塊?在 Kotlin 中就是一個 jar 包,因此這功能對 SDK 來講就是神器。
Kotlin Android Extension。使用後無需修改任何代碼,直接就能夠在代碼中使用 Xml 中聲明的任何的控件。
最後附上一段簡單的 kotlin 代碼
relativeLayout { textView { id = android.R.id.text1 text = "Loading..." }.lparams { centerInParent() } editText { id = android.R.id.edit hint = "Page Count for retain" inputType = InputType.TYPE_NUMBER_VARIATION_NORMAL }.lparams { below(android.R.id.text1) centerInParent() } button("click") { }.lparams { below(android.R.id.edit) centerInParent() }.onClick { println("hello world") } }.style { when(it){ is TextView -> it.textSize = 20f } }
以上 Go 和 Ruby 編寫 Android 應用的示例能夠見 AndroidDemoInOtherLanguages。其它 JVM 語言編寫 Android 應用的示例能夠見 AndroidDemoIn4Languages。
扯了這麼多可能有不少人以爲就這些怎麼可能實現低碳環保的編程。沒錯,你想的很對,要實現低碳環保的編程方式說到底只有惟一一個有效的方法就是說服你的項目經理或者其餘有話語權的人取消或修改掉那些不環保的須要,僅此而已。本次扯淡到此爲止。
做者信息:徐鴻福,多年後端及移動端開發經驗,現任 MaxLeap UX 團隊成員,主要從事於 Android 相關開發,目前對 Kotlin 和 Ruby 有濃厚興趣。
原文博客連接:https://blog.maxleap.cn/archives/592
歡迎關注微信訂閱號(發佈技術文專用):從移動到雲端歡迎加入咱們的MaxLeap活動羣:555973817,咱們將不按期作技術分享活動。