原文:The State of Native Android Development, November 2019原文:Vasiliy Zukanovandroid
翻譯做者: ronaldong面試
Android原生開發的生態一直在不斷地發展變化,過去5年從事android開發的經歷讓我深入的體會到了這一點。每隔2到3年,谷歌就會發布一些的新的開發指導建議、libraries、frameworks,我花了不少時間來認真審查這些變化並從中找出可能存在的問題。我相信許多Android開發者都有我這樣相似的經歷。數據庫
然而,2019年絕對是Android原生開發生態發生劇變的一年。在這一年裏,Android sdk添加了許多新的內容、重寫和移除了一些舊的內容,官方的開發者指南也進行了大幅度的更新。想要對Android開發有一種完整而又詳細的認識實在是太難了。後端
因而我寫下了這篇文章,我試圖去總結Android生態系統中所發生的事情,並對原生開發的將來作出一些預測。接下來我會把個人觀點分紅不一樣的章節來進行具體的闡述,文章的最後我會分享一些極具爭議的觀點。api
我但願這篇文章會對大家有所幫助,可是請記住,文章中確定遺漏了許多重要的內容,並且其中的許多觀點都是我我的的偏見。安全
AndroidX的預覽版是在一年半前發佈的。大約一年前它變得穩定了,與此同時Google也中止了對舊版Support Library的進一步開發。當我寫下這句話的那一刻,我想起了我以前在StackOverflow上提出的一個問題:Why does AOSP add new APIs to support libraries without adding them to SDK?,當時我是一個android開發新手,我想知道Support Library背後的動機,Googl爲何不直接把Support Library放到android sdk裏呢?服務器
不過使用「穩定」一詞來描述AndroidX彷佛有點諷刺,由於關於AndroidX的任何信息彷佛都不是穩定的。Google不斷的在往AndroidX裏添加新的庫和框架。命名空間和許多舊的API(目前還不到一年)正在以很是快的速度發展。多線程
到目前爲止,我已經將個人兩個應用遷移到了AndroidX。一切都很順利,但我也不以爲有多驚喜。Jetifier是一種將Support Library上的依賴項重定向到其AndroidX對等項的工具,轉換效果使人驚訝。可是即便應用程序不大,也並非「一鍵式遷移」。架構
我還參與了一個還沒有遷移到AndroidX的項目,沒有任何問題。在某些狀況下,彷佛我徹底不須要AndroidX。併發
總而言之,我想說的是:若是是開啓新的Android項目,那麼確定是應該使用AndroidX;對於現有的項目,我也建議您作好遷移到AndroidX的計劃,即便您如今看不到明顯的好處。不管如何,您極可能都須要遷移,所以最好按本身的計劃進行遷移,而不是之後當你須要一些新的AndroidX庫時進行緊急的遷移
在討論完AndroidX以後,就不得不提到Jetpack了。據我所知,Jetpack最初只是「architecture components」的工具集合,可是後來擴展爲包含了AndroidX的大多數(甚至全部)API的工具集合。所以,到目前爲止,我尚未看到AndroidX和Jetpack之間有任何有意義的區別,市場營銷和公關宣傳除外。
當您訪問Jetpack的官方網站時,它看起來不像是技術文檔,更像是早期SaaS初創公司的主頁。
看看這些「感言」:
再看看下面這些app:
若是Jetpack申請2020年獨立IPO,我不會感到驚訝,由於他們是如此的專一於營銷和公關。
不過說真的,這種向本身的生態系統中的開發人員「銷售」api的作法存在一些深層次的問題。好比,爲何有人真的想在搜索中宣傳ViewModel?
總而言之,因爲Jetpack的大部份內容都是來源於AndroidX,因此我以前寫的有關AndroidX的內容在很大程度上也適用於Jetpack。
下面,我將分別討論其中一些具體的API。
當應用程序不在前臺時讓應用也能執行操做是Android開發中最多見的場景之一。在引入doze模式、SyncAdapter、GCMNetworkManager、FirebaseJobDispatcher、JobScheduler以及最近的WorkManager以前,您能夠經過啓動服務(而不是綁定服務)來實現。這些都是Google本身的API,不過也有不少第三方解決方案,好比Android-Job。
可是,Google最近宣佈,他們將經過WorkManager API來統一後臺任務的調度。聽起來很不錯,可是因爲某種緣由,當我聽到這樣的聲音時,我總有種似曾相識的感受……
不管最終可否統一,WorkManager都沒法解決在執行後臺任務過程當中存在的一個最嚴重的問題:可靠性。我在這裏不作解釋,可是請記住,若是您須要在應用程序中執行後臺任務,請先閱讀dontkillmyapp.com上的全部信息。此外,請在Google的issue tracker中閱讀並加註星標。
Android系統的後臺任務執行與調度是一團糟,碎片化使得它很是細微且不可靠。
過去,我一直主張儘量的將數據同步等相似的工做放在後臺來執行,我多是SyncAdapter的最後一批粉絲。可是今天,鑑於可靠性問題,我主張相反的作法:儘量避免在後臺執行操做。若是您的PM堅持使用此功能,請向他們展現以上連接,並向他們解釋,後臺任務須要花費數百小時的時間來實現,並且帶來的麻煩多於收益。
有些時候執行後臺任務是不可避免的,可是在大多數狀況下,您能夠不這樣作。即便以給用戶帶來一些不便爲代價,它也多是最佳選擇。
毫無疑問,Room在衆多SQLite的ORM框架中佔據着主導地位。從2.2.0開始,Room支持增量註解處理。不過請記住,您的應用架構不該過於關心使用了哪一種ORM框架。所以,做爲architecture components的一員,Room只是市場術語,而不是技術角色。
Android開發中ORM框架的主要競爭者是SQLDelight。這個庫比Room還要老,可是據我瞭解,在過去的一年左右的時間裏,它已經被重寫了不少。不幸的是,它如今只針對Kotlin。另外一方面,SQLDelight支持Kotlin跨平臺。所以,隨着Kotlin使用率的增長,我預計SQLDelight的使用率也會隨之增長。
順便說一下,AndroidX中有對原生SQLite的使用說明,我還不知道該怎麼使用。可是若是您想在應用中使用原生SQLite,那麼你或許須要去認真的研究下這個主題。
此外還有許多針對Android的非關係型的數據庫,例如Realm,Parse,Firebase,ObjectBox等(其中有些仍在使用SQLite)。若是我沒記錯的話,它們中的大多數(甚至所有)都具備自動數據同步功能。一段時間以來,這些解決方案比較流行,但據我所知,它們已經不復存在了。可是我並不會立刻認爲非關係型的數據庫再也不重要了。
去年,我編寫了一個很是複雜的集成了Parse Server的Android應用。我使用了Android版本的的Parse SDK,體驗都很是好。若是您的公司已經僱用了許多後端開發人員,或者您須要實現許多服務器端邏輯,這可能不是最佳解決方案,可是對於僅在後端執行CRUD操做的初創企業和我的來講,這可能會是一種好的選擇。
可是我必須提醒的一點是:若是您要採用數據庫即服務的解決方案(例如Firebase),那麼請務必瞭解其長期的成本和影響。
關於外部存儲的開發,這裏有許多有「意思」的事情。
若是您應用的target sdk版本等於或者大於29,那麼你的應用將沒法再正常訪問手機外部存儲上的文件,除了少數幾種明顯的狀況。相反,您須要使用SAF框架(聽說),該框架容許用戶進行更精細的訪問管理。不幸的是,SAF的工做方式與以前徹底不一樣,所以某些應用程序可能須要進行重大重構。
Google但願從Android 10開始對全部的應用程序都實行這一要求,但它引發了開發者社區的強烈抗議,因而他們決定推遲此功能。所以,即便您的應用設置target sdk版本爲 29,它仍能夠在「舊版」模式下工做。可是,不管目標API級別是多少,下一版的Android系統都將對全部應用的存儲訪問範圍作更加嚴格的限制。
到目前爲止,我尚未使用SAF框架,可是從我在互聯網上閱讀的許多討論中看來,這多是一項艱鉅的任務。所以,若是您的應用程序還在以「舊版」模式使用外部存儲,那麼最好當即開始進行重構和測試。
幾周前,AndroidX系列中添加了一個新框架。它的commit message是這麼說的:
New library meant to replace SharedPreferences. The name is not final, this is just for implementation review and to support the design doc (feel free to request the design doc privately)[…]
目前咱們無需擔憂,但從長遠來看,彷佛SharedPreferences會被重寫,咱們須要使用這種新的方法。
SharedPreferences和這個新框架之間的主要區別在於,默認狀況下後者是異步的。換句話說,您須要實現一個回調以獲取特定鍵的值,該回調將在之後的某個時間收到通知。
若是您對這種異步通知的機制感到好奇,則能夠閱讀StackOverflow上的這個答案。Reddit用戶Tolriq在這裏分享了他們遇到此bug的機率。在他們的應用中,這個bug會影響1 / 10,000 / SESSIONS_PER_USER_PER_MONTH的用戶。對於通常的應用程序,這可能微不足道。可是在須要高可靠性的狀況下,這可能會引發嚴重的後果。例如,在裝有Android Auto的汽車中,應用程序掛起和隨後的崩潰會分散駕駛員的注意力,這可能會致使很是不幸的後果。
在依賴注入方面,最大的變化就是Dagger-Android的棄用。這裏我想解釋兩點:首先,我說的棄用並非指「正式」棄用,由於它還沒有正式棄用。其次,Dagger-Android並非整個Dagger2框架,而只是相對較新的功能。我在這個主題上寫了一篇很是詳盡的文章,因此我在這裏再也不重複。
至於其餘依賴注入框架,我不認爲它們是Dagger的真正競爭者。例如,Koin也許不錯,但我認爲它不會吸引不少人。實際上,我相信它僅因爲兩個主要緣由而獲得了初步採用。第一個是Dagger的糟糕文檔,Koin在這方面要比Dagger領先N光年。第二個緣由是Koin是用Kotlin編寫的,它藉着kotlin發展的浪潮開始興起。到目前爲止,這波浪潮已經幾乎消逝。
我認爲可能會發生的狀況是,純依賴注入的框架(又稱爲手動依賴注入)的會逐漸出現。
如今,谷歌聲稱「隨着應用程序的不斷增大,手動依賴項注入成本呈指數增加」。我認爲,這僅代表他們既不瞭解「指數」的含義,也沒作過任何實際的「測量」。此聲明是徹底錯誤的,我但願Google不要以這種方式來誤導社區裏的開發者了。
事實上,純依賴注入在後端開發中很是廣泛(尤爲是在開發微服務的時候,您不想在其中添加對每一個服務的框架的依賴),反射也是後端開發中的一個有效的選項。所以,若是要使用依賴注入框架,他們一般不須要解析編譯時代碼。
可是,Android開發的狀況有所不一樣。因爲咱們不能使用反射式DI框架,因此咱們使用了Dagger。事實上,咱們可使用反射式DI框架,而且對於大多數項目來講均可以,可是卻存在性能問題。我並非說使用反射式DI框架是安全的,但它絕對不是一種非黑即白的方案。不管如何,Dagger已是在Android開發中使用依賴注入的事實上的標準,咱們都使用它。但使用Dagger的代價也很明顯:
換句話說,雖然Dagger確實容許您編寫更少的代碼,但因爲它會影響構建時間和所需的培訓時間,所以在大型項目上它會花費更多的時間。
在大型項目中,構建時間慢纔是真正的問題,併成爲主要的生產力瓶頸。所以,儘管Dagger確實提供了很是出色的功能來簡化DI(固然,一旦您知道如何使用它),但我相信咱們對純依賴注入會產生愈來愈多的興趣。
開發人員採用DataBidning的主要緣由之一是再也不須要調用findViewById()了。老實說,findViewById確實很冗餘,我也不介意擺脫它們。可是,在我看來,調用findViewById()帶來的小麻煩並不能證實使用DataBinding是合理的。好消息是,很快咱們將可以使用另外一個新功能ViewBinding來刪除這些findViewById()的調用。
實際上,我歷來都不相信DataBinding。對於它(應該)解決的問題,我感受太複雜了。此外,DataBinding容許開發人員將邏輯放入XML佈局中。經驗豐富的開發人員是不會使用這種方法的,由於這增長了項目維護的難度。這是DataBinding框架的另外一個缺點。
早在2016年11月,當DataBinding正處於大肆宣傳的頂峯時,我在StackOverflow上的一個答案中作出瞭如下預測:
However, there is one prediction I can make with a high degree of confidence: Usage of the Data Binding library will not become an industry standard. I’m confident to say that because the Data Binding library (in its current implementation) provides short-term productivity gains and some kind of architectural guideline, but it will make the code non-maintainable in the long run. Once long-term effects of this library will surface – it will be abandoned.
如今,關於DataBinding的使用率,我沒有任何統計數據,可是很明顯,它並無成爲行業標準。我本身還從未見過使用DataBinding的專業項目,也不多見到在其應用中使用DataBinding的開發人員。據我估計,一旦ViewBinding成熟並被普遍採用,DataBinding將會更加流行,併成爲「傳統」框架。
自從引入ViewModel以後,在Android應用中對於配置更改的處理就變得一團糟。我知道個人這種說法太苛刻了點,但實際上,這是我能夠描述的最溫和的表達方式。
對我來講幸運的是,Gabor Varadi(又名Zhuinden)已經在Reddit上的這篇文章中對這一問題進行了總結,因此我不須要本身作。他的結論就是:不推薦使用onRetainCustomNonConfigurationInstance(),而推薦使用ViewModel。有趣的是,在該帖子的結尾,Gabor作了一些頗具嘲諷味道的預測:
你發現什麼了嗎?Retained Fragments如今已經被棄用了! 。
我認爲,棄用Retained Fragments其實是一個好主意。Fragment的生命週期裏具備onAttach()和onDetach()這兩個方法的惟一緣由就是爲了支持Retained Fragments的使用。經過棄用Retained Fragments,這些方法也能夠棄用,而且能夠簡化Fragment的生命週期。若是您使用個人方法來處理Fragment的生命週期,那麼這種棄用就不會讓您感到困擾,由於我長期以來一直建議您避免Retained Fragments,忽略onAttach()和onDetach()方法。
儘管有充分的理由要棄用Retained Fragments,但棄用onRetainCustomNonConfigurationInstance()倒是胡說八道。這不是我說的,而是Jake Wharton說的(您能夠在前面提到的Gabor在Reddit上的帖子下閱讀他的原話)。
爲何要作這些變更呢?我只能看到一種解釋:Google決定無論其它技術優點如何,都強制將全部Android項目遷移到ViewModel。他們願意棄用全部現有的替代方案以實現其目標,即便這些替代方案實際上優於ViewModel自己。
聽起來有點陰謀吧?我贊成。可是,幸運的是,咱們能夠對此理論有一個簡單的檢驗。
雖然我不喜歡Preserving State on Configuration Changes,但它不會以任何方式影響我,由於我沒有使用它。實際上,絕大部分應用程序都不須要它。它們也不須要ViewModel。正確處理Configuration Changes的方式就是在onSaveInstanceState(Bundle)回調方法裏增長處理邏輯。這是一種更簡單,更好的方法,由於它還能夠處理保存和恢復流程(也稱爲進程終止)。所以,只要我能以這種方式保存狀態,就能夠了。儘管Google進行了大量的營銷和公關工做,但許多經驗豐富的開發人員都意識到ViewModel太複雜了,而且有更好的方法來保留配置更改的狀態。
所以,若是Google確實有別有用心,而且想迫使全部項目都使用ViewModel,那麼他們還須要棄用onSaveInstanceState(Bundle)。我知道這聽起來很瘋狂,但這其實是件好事,由於若是這種瘋狂的預測成真,您就會知道基礎理論是正確的。
可是,鑑於Android的內存管理機制,Google不能僅在不提供可靠替代方案的狀況下就棄用onSaveInstanceState(Bundle)。「幸運」的是,這些變化已經應用在ViewModel的保存狀態模塊上了。
我想在一兩年內咱們就會知道這種作法是否有任何優勢。‘
總而言之,正如我在本節開頭所說的那樣,自ViewModel發佈以來,Android中的Configuration Changes就成了屎。兩年多之前,當我撰寫題爲「Android ViewModel Architecture Component Considered Harmful」的文章時,我預測ViewModels將是一種浪費。個人全部預測都是真實的,但不幸的是,事實證實真相比這還糟。
在併發這方面,最大的變化就是AsyncTask的棄用。我已經寫了一篇有關此主題的很是詳細的文章,並提出了具體建議,所以在此再也不贅述。
接下來我說的話可能會使部分讀者感到不滿。拜託,別太把這事當真。
Android開發中另外一個流行的多線程框架RxJava很快就會成爲「過去式」。從下面這幅StackOverflow趨勢圖能夠明顯看出:
許多開發者會質疑個人觀點,稱該數據不具備表明性,而且還有其餘方法的能夠解釋該圖。他們多是正確的,由於我本身也不是數據科學家。可是,在此圖中,我看不到任何其餘關於峯值的解釋,並且RxJava的曲線與AsyncTask的曲線具備相同的斜率。
所以,若是您還沒有花時間在學習RxJava上而且您的項目沒有使用它,那麼我建議您避免使用它。實際上,這一直是個人建議,今天它也獲得了數據的支持。
若是您的項目已經使用了Rx,也請不要驚慌,您無需當即重構任何東西。可是,請記住,從此找到具備Rx經驗的開發人員將愈來愈困難。所以,在項目中普遍使用Rx可能須要新的開發人員投入更多的時間。最終,普遍使用Rx的項目將被視爲「not cool」(例現在天使用AsyncTask和Loaders的項目)。
我知道個人這些觀點對於許多開發人員來講很不友好。他們花了數週時間來學習RxJava,甚至說服了同事在項目中使用RxJava,如今我卻說它會成爲「過去式」。我只想說我只是分析實際狀況並根據我所看到的作出預測,我多是錯的,也多是對的。
在Kotlin語言中,咱們可使用協程。我最近使用協程實現了一些複雜的用例,發現此框架很是的細微和複雜,而且相對不成熟,我甚至發現了一個bug。
有一種流行的說法是,協程使得併發處理更簡單。我歷來不這樣認爲,由於我知道併發是很是複雜的,可是在我有了一些實踐經驗以後,我能夠自信地說,協程並無想像中的那麼美好。在我看來,協程實際上增長了程序複雜性,因此我建議大家當心地使用它們。
另外一方面,協程彷佛將成爲Kotlin語言裏處理併發操做的默認方式。所以,我認爲若是您編寫Kotlin代碼,您須要投入時間並學會使用它們。
據我所知,目前還有一個流式框架,它在協程之上添加了流處理操做符。幾個月前才穩定下來,因此我如今還不能說什麼。
如今讓咱們來討論一下Kotlin。根據以往的經驗,我知道這是一個很是敏感的話題,並且無論我描述的多麼客觀,最終都會遭受一些開發者的攻擊。然而,我認爲在總結原生Android開發現狀的時候跳過Kotlin是極不誠實的。所以,我再次請你不要把我說的話當真。
你所須要知道的一個重要的事實是:在Android開發中使用Kotlin會嚴重增長你的構建時間。
在這篇文章中,您會了解到我在使用Kotlin進行開發時對構建時間所進行的統計測試的結果。clean build 增長了18%的構建時間,incremental build 增長了8%的構建時間。
Uber與JetBrains也聯合發表了他們本身的研究結果,他們的結果更爲負面。若是您不在應用程序中使用註解處理器,那麼引入Kotlin可能會使您的構建時間增長四倍!若是您使用了註解處理器,那麼引入Kotlin會使您的構建時間增長50%-100%。
Uber的研究結果與將OkHttp遷移到Kotlin版本後構建時間增長了4倍的結果是一致的。
若是您對這些數字感到驚訝,您不用擔憂-這不是您的錯,並且您並不孤單。儘管這個事實極爲重要,但它並未獲得普遍討論,而且我以爲Google也試圖迴避這個事實。我曾與Google內部一個熟悉此事的開發人員有過一次很是有趣的討論,我問他是否能夠討論下這個話題,他說:「我不喜歡;我不喜歡;我不喜歡。這是一件很微妙的事情。」
除了增長構建時間以外,Kotlin還不支持增量註解處理,而在大約10個月前Java就已經支持增量註解處理了。
兩年前,我寫了一篇文章來警告開發者們在早期使用Kotlin時可能會遇到的潛在風險。在很長一段時間內我被稱爲「kotlin的討厭者」。
可是,若是您今天閱讀這篇文章,您會發現我實際上低估了這些問題的嚴重性。在大型的Android項目上,構建時間是最糟糕的生產力殺手之一,並且即便在今天,即Kotlin被官方「正式採用」兩年多以後的今天,Kotlin仍然不如Java。無論Kotlin帶來什麼其餘好處,全部這些均可能因爲更長的構建時間而被否認。
也就是說,咱們不該改忽視這樣一個事實:是谷歌將android開發的生態強行推向了kotlin,使得其使用率在穩步上升。
就我我的而言,我並無在我目前已經開始的新項目中選擇kotlin語言,我不想在kotlin上浪費我本身的時間。不過,從如今開始,我會認真考慮使用kotlin來開發新項目,我已經在幾個demo上嘗試過了。可是我不一樣意開發人員說你必須在新項目中使用Kotlin,這仍然是一種權衡。
至於大家是否應該將現有項目遷移到Kotlin,我沒法提供任何通常性建議,您須要根據具體的狀況進行仔細的分析。可是,若是您確實決定開始(或已經開始)遷移,那麼這個帖子可能會對您有用。
在過去的兩年中,我開發了三個新的應用程序。我認真研究了現有的項目並分析了早期技術決策所帶來的長期影響。我寫了一些博客,提供有關Android開發的高級課程。我花了不少時間在互聯網上討論Android開發相關主題。
儘管如此,我仍是感受本身沒法跟上Android生態系統的變化。
若是是這樣的話,對於那些缺少經驗、須要指導的Android開發人員,我深表歉意,並且我至今沒法想象從頭開始學習Android開發的感受。當您對框架和工具感到滿意的時候,其中許多將已過期或即將過期。加入這個本來很棒的社區多是最糟糕的時刻。Google爲他們的「包容性」感到很是自豪,但看起來它不適用於經驗不足的開發新手。
我我的認爲Google對Android框架所作的更改會致使巨大的人類潛力浪費。閱讀全部這些更改須要花費數小時,更不用說實際實施它們了。我寧願花更多的時間來創造價值,而不是追逐本身的尾巴。
在這篇文章中,我試圖總結有關Android原生開發現狀的一些重要的內容,我還對將來作了一些預測。這篇文章並不完美:它可能包含一些錯誤,並且還錯過了一些其餘重要內容。請隨時在下面的評論中糾正我。可是請記住,本文沒有任何私人內容。我知道我提出了一些很是有爭議的觀點,可是我相信這是對的。
我還在本文的多個地方引用了我以前寫的一些文章。我這樣作並非爲了炫耀並說「看,我是正確的!」,而是讓您可以瞭解我過去的預測並將其與實際發生的狀況進行比較。當我寫這些文章時,他們讀起來就像您今天讀本篇文章同樣瘋狂。可是我所作的預測卻很是準確。
固然,我也想說:「看,我是對的!」。我冒着巨大的專業風險發表了這些有爭議的預測,在得知本身沒有誤導讀者後我感到很是的欣慰。即便有時候我寧願本身是錯的,也但願Google成爲真正的合做夥伴。可是到目前爲止,狀況並不是如此。
最後附上文章做者對於跨平臺開發的一些見解,僅供參考。
在這裏小編也分享一份私貨,本身收錄整理的Android學習PDF+架構視頻+面試文檔+源碼筆記,還有高級架構技術進階腦圖、Android開發面試專題資料,高級進階架構資料幫助你們學習提高進階,也節省你們在網上搜索資料的時間來學習,也能夠分享給身邊好友一塊兒學習
若是你有須要的話,能夠點贊+評論,關注我, 加Vx:15388039515(備註思否,須要進階資料)