寫在前面
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供建陽網(wǎng)站建設(shè)、建陽做網(wǎng)站、建陽網(wǎng)站設(shè)計、建陽網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、建陽企業(yè)網(wǎng)站模板建站服務(wù),十載建陽做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
如果你只是一個想成為 Android 開發(fā)者的人,并且還沒有寫過任何應(yīng)用,那么這篇文章對你來說,還有點太早。本文主要是為了幫助開發(fā)者成為一個更專業(yè)的人。
本文,我會給你很多建議,不會讓你空手而歸。文章中列出了如何在短時間成為一個專業(yè)的開發(fā)者。讀完文章,需要你自己去練習,并時?;貋砜纯催@些技能。
在本文開始之前,我就當你已經(jīng)在 Google Play 發(fā)布過 Android 應(yīng)用并且使用 GitHub 來進行源碼管理。
Android 是一個非常復雜的框架,它擁有陡峭的學習曲線。有一些復雜的概念的確是 Native 的 Android 開發(fā)者需要學習的,但另一部分卻是由于 Android 的原因,造成了它的復雜度。
當你向?qū)I(yè)進軍時,除了你的軟件開發(fā)工作以外,你應(yīng)該學習 Android 框架,忘記語言、架構(gòu)、流行的開源庫,專注于核心概念,并進行深入的研究。
具體來說,我建議你更多的了解以下內(nèi)容:
Android 內(nèi)存管理和進程調(diào)度
當面臨「Low Memory Killer」的時候,如何保證你的應(yīng)用程序穩(wěn)定可靠的運行?這是一件很復雜的事情。長話短說,當用戶切換到其它應(yīng)用時,你應(yīng)用的生命周期就會被打亂,但是當用戶過一會兒重新切換回來的時候,用戶卻希望你的應(yīng)用程序像任何事情都沒有發(fā)生過一樣,正常運行。
在本文中,我并不會介紹內(nèi)存管理的任何細節(jié),如果你想了解它們,可以看看這篇文章。
生命周期
如果有人要我說出 Android 應(yīng)用程序中的復雜度和 Bug 的主要來源,我會立馬大聲告訴他是“生命周期”(然后捂住臉哭)。
Application、Activity、Fragment、Service、BroadcastReceiver、ContentProvider 和一些 Android 框架的核心組件,都擁有復雜的生命周期,并且它們的生命周期還不一樣。如果你覺得這還不夠多,Google 也一直在推出新的庫和框架,這些庫都有自己的復雜性和獨立的生命周期。Loader, ViewModel 和 LiveData 都是為了解決這些問題而推出的。
有件有意思的事情,我從來沒有看到過任何有關(guān)“生命周期“的定義。我們一直在使用它,但是它到底是什么意思呢?據(jù)我所知,在某種程度上,你只是把一些節(jié)點串聯(lián)在一起,構(gòu)建出一個生命周期的圖。我對生命周期有過很多的思考,在這里,我將嘗試對它進行定義。
組件的生命周期是一個抽象的狀態(tài)機。這里的抽象的意思是指,這些狀態(tài)機的狀態(tài)是預(yù)先定義好的,它們之間的轉(zhuǎn)換條件也是定義好的。但是這些定義是不完整的。你需要去實現(xiàn)缺少的部分,使他們可以正常工作。這些缺少的部分是這些組件方法的子集,我們稱其為“生命周期回調(diào)”,除了狀態(tài)機本身之外,這些生命周期回調(diào)中,也有很多隱式的限制和約束。這些限制有些寫在了文檔中,而有些卻并沒有記錄。
生命周期到底有多復雜?我們先來看一下這張圖 (它有點不完整,還有點過時)。這張圖,看起來有點可怕。不過,你也不要慌,大多數(shù) Andorid 開發(fā)者都搞不明白這個圖。事實上,即使 Google 的 Android 開發(fā)者也搞不明白生命周期的問題。Google 在發(fā)布 Lifecycle 組件的時候,里面引入了一些有關(guān) Fragment 的 bug, 直到后續(xù)的新版本發(fā)布了才得以修復。
雖然現(xiàn)在你不需要完全掌握 Android 的生命周期,但是你必須要知道一些重要的細節(jié)。否則,你的代碼會變得混亂不堪,并且容易出現(xiàn)一系列難以解決的問題。我寫了兩篇文章 Activity 生命周期與 Fragment 生命周期 ,描述了生命周期的細節(jié)。當你不知道如何使用 onStart 和 onResume 時,你可以去看看這兩篇文章。
當你掌握了生命周期的基礎(chǔ)知識,你可以去看看 Gabor Varadi 寫的 Android 開發(fā)的十宗罪 ,這篇文章,列舉出了大多數(shù)開發(fā)者都會犯的錯誤。這些錯誤大多數(shù)都與生命周期有關(guān)。
順便說一下,在面試中,生命周期相關(guān)的問題也會被經(jīng)常問到。這也是你必須好好學習生命周期的原因。
Context
在每一個 Android 應(yīng)用程序中,都有一個或多個上下文對象。
和生命周期一樣,它也很難被解釋。它就像是一個“上帝類“一樣,它有非常多的能力。我們很難用一兩句話就把它描述清楚。盡管如此,理解 Context 職責和不同 Context 之前的區(qū)別也是非常重要的。
本文中,沒有更多關(guān)于 Context 的內(nèi)容,我建議你去讀一下 StackOverflow 中關(guān)于 《What is 'Context' on Android?》 的回答和這個回答的內(nèi)容.
UI 線程
每一個 Android 應(yīng)用程序都有一個特殊的線程 —— UI 線程。這一個線程在屏幕上繪制出 UI 頁面。如果你讓 UI 線程超負荷運行,你的應(yīng)用程序?qū)兊每D,不響應(yīng)。在極端情況下,UI 線程中的錯誤會導致整個應(yīng)用程序出錯(至少看起來像是出錯了)。
如果你想詳細了解線程背后的機制原理,你可以去看這個視頻,視頻中詳細解釋了 Android 中的多線程,包含 UI 線程的相關(guān)細節(jié)和可能存在的問題。
邏輯拆分
從整體上說,Android 框架的代碼很不“整潔”。它包含著很多的上帝類,這些類中,每一個有數(shù)千行代碼,并且我們還必須去擴展這些類,才能讓我們的應(yīng)用程序運行起來。在多數(shù)情況下,不管是 Application, Activity ,F(xiàn)ragments 還是 Service,我們都是在一個很大的類中,做很多的事情。
雖然在 Andorid 開發(fā)中,這是一個常見的做法,但這樣子做并不利于長期維護我們的代碼邏輯。因此我建議,要盡可能的注意這個問題,多找機會去重構(gòu)代碼,將邏輯拆分到獨立的類中去。
說實話,我現(xiàn)在并不認為,一個初級開發(fā)者可以對架構(gòu)和設(shè)計做出太多的改善工作。正確的封裝代碼邏輯,提取出有意義的類,都需要一些開發(fā)經(jīng)驗。當然,我也不希望你不去思考代碼拆分,你可以做一些力所能及的事情,避免出現(xiàn)不可控的情況(例如,一個 Activity 中寫了超過 5000 行代碼)。
剛開始,你可以嘗試拆分這篇文章中描述的與 Context 有關(guān)的邏輯。
當你在你的職業(yè)生涯中工作幾年,你變成經(jīng)驗豐富的 Android 開發(fā)者,通過研究和學習,你可以很輕松的實現(xiàn)一些非專業(yè)化的功能。那下一步,你該做什么?
我認為,在這個時候,你已經(jīng)很熟悉 Android 框架的基礎(chǔ)知識了,可以嘗試去學習更高層次的技能。這些技能不局限于 Android,它們是一些通用的軟件開發(fā)的技能。具體來說,你可以研究以下主題:
依賴注入
依賴注入是一個關(guān)注結(jié)構(gòu)分離的設(shè)計模式。它主要是用來進行分離應(yīng)用程序的兩個功能:應(yīng)用程序和核心功能、核心功能組件實現(xiàn)之間的鏈接。
從某些方面來說,實現(xiàn)了依賴注入的代碼庫就好你一個計算機:依賴注入的基礎(chǔ)庫就像是主板一樣,而其他的功能組件就好像是 CPU、內(nèi)存、外設(shè)等。只要你的代碼中實現(xiàn)了依賴注入,你就可以很方便的插入新功能,并且可以很容易的重用其它組件的功能,也可以很方便的使用新組件的功能。雖然這個比喻有點夸張,但是在我看來,它也確實很好的反映了依賴注入背后的思想。
不幸的是,現(xiàn)在關(guān)于依賴注入的文章,很多都存在誤解,這給初學者帶來很多干擾。因此,如果你想學習依賴注入,我建議你讀一下這篇文章,本文中,我分析了眾多依賴注入的“神話“。
UI 分離
由于 Android 框架本身的架構(gòu),造成了我們在開發(fā)的過程中,使用戶頁面與應(yīng)用程序中的其它邏輯耦合在一起。幾乎所有的 Android 初學者都會這樣。這種耦合會導致我們寫一個很大的類,這個類里面有應(yīng)用程序的 UI 繪制、網(wǎng)絡(luò)處理、多線程處理、應(yīng)用業(yè)務(wù)邏輯等。
根據(jù)我的經(jīng)驗,UI 邏輯與其它邏輯耦合在一起,會導致代碼的可維護性越來越差,遲早會使用代碼變得難以理解,無法閱讀。到最后,可能會因為功能上的一點小變化,引起很大的副作用。
要將 UI 邏輯與其它邏輯進行分離,可以用使用 Model- View - X 的架構(gòu)模式。例如: Model-View-Contoller(MVC)、Model-View-Presenter(MVP)、Model-View=ViewModel(MVVM)。這些架構(gòu)模式都屬于同一類架構(gòu),當然,這一類架構(gòu)不僅僅包含列舉的這幾個,還有其它的架構(gòu)模式。在這里,為了更方便的描述這一類架構(gòu)模式,我把他們統(tǒng)稱為 MVx 模式。
當你在學習 MVx 模式的時候,請記住,這些都不是架構(gòu),而是一種架構(gòu)模式。這些架構(gòu)模式僅用于 UI 展示邏輯。因此僅僅使用 MVx 并不能給你一個好的架構(gòu),要有一個好的架構(gòu),你還需要在其它方面做出更多的努力才能實現(xiàn)。
多線程
有經(jīng)驗的 Android 開發(fā)者都會了解多線程,并且了解他們對應(yīng)用程序的影響。你也許會說,我精通 AsyncTask、RxJava、協(xié)程等。我想表達的多線程不是你理解的這個。會使用多線程框架并不等同于理解多線程。
舉個例子,眾多 Android 開發(fā)者都認為,使用 AsyncTask 會導致內(nèi)存泄漏。這個觀點來自 Android Studio 默認的多線程 lint 規(guī)則中。既然如此,那這個觀點就是對的了嗎?很不幸,這個觀點是錯誤的。在這里,我不講解它們的細節(jié),你可以讀一下這篇文章,里面有很多關(guān)于 AsyncTask 的內(nèi)容。
我認為要理解多線程程,就必須可以使用任何多線程框架,甚至是基于基礎(chǔ)的 Thread ,都可以寫出正確的并發(fā)代碼。要實現(xiàn)這個目標,你不僅僅需要知道你喜歡的多線程庫的 API,你還需要理解多線程的細節(jié)。這些多線程庫雖然好用,但如果你不理解多線程的基礎(chǔ)細節(jié),那么你的應(yīng)用程序出現(xiàn)多線程的問題只是時間問題。
如果你想學習多線程,從這個視頻 開始,視頻中講解了所有 Android 開發(fā)人員都需要知道的基本概念與原理。
自動化測試
據(jù)我所知,很多 Android 項目,都沒有使用任何的自動化測試。在使用自動化測試的項目中,大多數(shù)也是 QA 人員使用 Appium 之類的工具來完成的。這是整個 Android 行業(yè)的現(xiàn)狀,非??杀?。之所以沒有自動化測試,這個問題可以追溯到 Android 起源,Google 也在很長一段時間里,沒有關(guān)注過第三方應(yīng)用的自動化測試。
現(xiàn)如今,有單元測試和 UI 自動化測試經(jīng)驗的開發(fā)者需求量很大。即使你到一家沒有使用過任何自動化測試的公司去面試,如果你說你會自動化測試,就會給你的面試加分。反之,如果你去的是一個廣泛使用自動化測試的公司,你沒有自動化測試的技能,這會給你面試減分,處于劣勢。
因此,我建議每一個 Android 開發(fā)者都去學習一下自動化測試的相關(guān)知識。就個人而言,我更喜歡單元測試。而一些開發(fā)者喜歡 UI 自動化測試。所以,可以選擇一個你更感興趣的技術(shù),嘗試一下。
如果你對 Android 已經(jīng)有了非常豐富的開發(fā)經(jīng)驗,那么,是時候?qū)W習一些“元”技能了,并且在特定領(lǐng)域進行深度研究。在我看來,以下技能對專業(yè)的開發(fā)人員來說,都是非常不錯的方向。
技術(shù)方案評估
如果你還沒有做過這件事情,那么現(xiàn)在是時候開始做了。每一個重要的技術(shù)決定,都需要進行評估、權(quán)衡。有時候,這種決定帶來的結(jié)果非常好,立竿見影。但是大多數(shù)時候,并非總是能夠立竿見影,看到效果。通常情況下,需要決策的范圍越大,所涉及到的評估范圍就越大,除了可以簡單進行決策的事情,還有很多可評估項都是非常抽象,短時間內(nèi)根本看不到結(jié)果的。
在自己豐富的經(jīng)驗水平下,面對眾多選擇,你至少應(yīng)該知道如何找到取舍。如果你能對技術(shù)方案評估提供有用的建議,你就非常優(yōu)秀了。技術(shù)方案評估權(quán)衡這是一項非常復雜的技能。通常,在與其它開發(fā)者、項目經(jīng)理甚至是其它部門員工討論的時候,你能找到折中方案,就能進行方案評估。因此,在大數(shù)情況下,你只需要掌握評估方案的能力就夠了。
那我們所說的“技術(shù)方案的評估”到底是什么意思?說實話,很難具體說明它是什么。不過,我們可以提供一些反例,來解釋為什么不適合在開發(fā)中使用。舉個例子:
我們應(yīng)該將多線程的使用遷移到 RxJava, 而不是 AsyncTask, 因為 AsyncTask 會導致內(nèi)存泄漏。
正如我前面所說,AsyncTask 并不會導致內(nèi)存泄漏。所以上面這句話是錯誤的。說這句話的開發(fā)者并沒有深入的研究多線程。此外,他也沒有提到 RxJava 的問題。對于一個項目中的開發(fā)人員來說,RxJava 存在一個很陡峭的學習曲線。
我們應(yīng)該為我們的新代碼寫單元測試,并且設(shè)定一個長期的目標,覆蓋所有的代碼,以確保我們的代碼質(zhì)量。
這句話包含幾個前提,首先,我們現(xiàn)在開始單元測試是不可能的,至少需要開發(fā)人員投入時間來學習這種技術(shù)。編寫單元測試是一個很明智的決定。我們不能為所有代碼編寫單元測試,因為有一些部分是不穩(wěn)定的。最后,達到特定的覆蓋目標并不會自動提高“質(zhì)量“。在這個例子中,開發(fā)者并不了解單元測試,他們無法確定在項目中使用單元測試所涉及的問題和影響。
我希望,你對“技術(shù)方案評估”已經(jīng)有了大致的想法,如果你有一個重要的決定,你需要完成所有必要的調(diào)研,如果你依然看不到整個評估中存在的復雜網(wǎng)絡(luò),那可能是你的調(diào)研沒有做好。在做決定的時候,有些事情可能超出技術(shù)范圍,你也需要考慮你的決策對其它部門同事的影響。
專業(yè)領(lǐng)域
如何區(qū)分一個技術(shù)專家和一個普通開發(fā)者?是我們熟悉的概念的數(shù)量嗎?我認為,在技術(shù)方面,區(qū)分是否是專家主要在于知識上的深度。
作為一個技術(shù)專家,你應(yīng)該有一個或者多個專業(yè)領(lǐng)域。你知道這些領(lǐng)域的詳細細節(jié),比一般的開發(fā)者知道的要多得多。你需要持續(xù)深入的研究,來保證你的專業(yè)深度,了解專業(yè)領(lǐng)域的最新發(fā)展,不會對新的工具和技術(shù)感到驚訝。此外,即使你并沒有在任何項目中使用某些技術(shù),你也需要研究這些技術(shù)使用上相關(guān)聯(lián)的各種成本。
現(xiàn)如今,有一個自己的專業(yè)領(lǐng)域很難。這不是從博客中挑選幾篇好文章進行閱讀就可以的,也不是讀完幾本好書、上完幾門好課就可以的。當然,通過這些內(nèi)容進行學習,對你的專家之路都是有幫助的,但是要有自己的專業(yè)領(lǐng)域,唯一的方法就是積極參與其中進行學習研究并獲得大量經(jīng)驗。
我很喜歡物理學家尼爾斯·玻爾說的這句話:
An expert is a man who has made all the mistakes which can be made, in a narrow field.(專家就是把領(lǐng)域內(nèi)所有該犯的錯都犯完的人。)
我們可以在哪些領(lǐng)域進行深入研究呢?實際上,幾乎所有的都可以進行深入的研究,在軟件開發(fā)領(lǐng)域,沒有任何一個領(lǐng)域會因為太小而不能設(shè)置成專業(yè)目標。對此,我也有一些建議:
UI
構(gòu)建系統(tǒng)
離線工作
并發(fā)
NDK
持續(xù)集成
性能
架構(gòu)
監(jiān)測
項目管理
專業(yè)知識領(lǐng)域
還有很多很多。需要注意的是,上面我列出來的內(nèi)容,一些并不屬于嚴格的技術(shù)領(lǐng)域。只要你能為你的雇主產(chǎn)生價值,你可以選擇你喜歡的任何領(lǐng)域并進行深入研究。
我認為,一個 Android 技術(shù)專家,至少有 2~3 個專業(yè)領(lǐng)域,例如,我的專業(yè)領(lǐng)域是:架構(gòu)、單元測試、并發(fā)、依賴注入。我相信,在不久的將來,我能夠?qū)ⅰ爸貥?gòu)祖?zhèn)鞔a”添加我的專業(yè)技能列表里面。