如何成為一名進(jìn)階的Android開發(fā)者

*本文Notion weblink。歡迎直接評(píng)論,提出寶貴建議:
https://learned-stay-51d.notion.site/Android-960b53ff4af2496bbf55a4f932ae4beb
閱讀時(shí)長(zhǎng)大約30分鐘
前言
文章內(nèi)容原為我在前公司開的一門內(nèi)部課程,面向剛剛進(jìn)入公司,從事Android開發(fā)校招生。做了內(nèi)容脫敏后分享在這里。
寫這篇文章的初衷是希望能讓讀者更好的進(jìn)入Android開發(fā)者的角色。比起市面上五花八門的Android視頻課程,這篇文章不會(huì)聚焦在技術(shù)的使用和實(shí)現(xiàn)上,而是更多的是集中在以下幾個(gè)方面:
如何去了解項(xiàng)目使用的語言、組件、架構(gòu)、代碼風(fēng)格等
使寫出來的代碼有章法。滿足可靠、可拓展、可維護(hù)這樣的原則
如何調(diào)試代碼,當(dāng)執(zhí)行遇到問題時(shí)使用合適的工具排查
一些Tricks,可以單位時(shí)間內(nèi)產(chǎn)出更多,下班更早(Maybe)
簡(jiǎn)單的自我介紹
從事Android開發(fā)八年,大廠、外企都呆過,既從零搭建過很多新項(xiàng)目,也維護(hù)過很多日活千萬的應(yīng)用。
To be a developer for Android
如果你跟我一樣,在上崗成為Android開發(fā)者之前,并沒有系統(tǒng)的學(xué)習(xí)過Android開發(fā),那么經(jīng)常翻閱Android門戶網(wǎng)站(https://developer.android.com/)是一個(gè)非常好的習(xí)慣。里面包含但不限于:
入門開發(fā)課程(十分推薦新手們按照課程實(shí)操一遍)
API Docs
一些官方推薦的第三方庫
Android OS最新版本Features
App上架Play Store的政策
你可能已經(jīng)習(xí)慣開發(fā)中遇到問題時(shí),通過Stack Overflow等渠道,描述問題的指征,并尋找靠譜的答案。這里建議你不妨轉(zhuǎn)換下思路,下次遇到類似的情況時(shí),先嘗試翻翻API docs等,有些比較基礎(chǔ)的問題可能早已經(jīng)寫在doc中了。
更重要的是,在查閱doc的過程中,你會(huì)閱讀到一些上下文信息(比如這個(gè)類的其他API、用法和注意事項(xiàng)),相較于之前尋找答案的方式,你可能會(huì)獲得許多額外的知識(shí),這會(huì)更有助于你了解一個(gè)類、一個(gè)組件、一個(gè)框架的全貌,聞一而知十。
Android Studio
這是你打開Android Studio后看到的景象。默認(rèn)設(shè)置下,整個(gè)IDE會(huì)被劃分為這五個(gè)區(qū)域:

左側(cè):樹形結(jié)構(gòu)的方式展示項(xiàng)目的文件
底部:一些編譯、運(yùn)行時(shí)的監(jiān)視窗口,命令行,性能監(jiān)控等
右側(cè):Gradle Tasks列表,模擬器,布局預(yù)覽等
頂部:一些功能的快捷入口,比如編譯、Git等
中部:代碼編寫區(qū)域
如果屏幕不是特別大,可以按工作需要展開、折疊部分區(qū)域,以突出重點(diǎn),節(jié)省視力。比如Coding時(shí)一般只需要代碼編寫區(qū)域和左側(cè)的項(xiàng)目結(jié)構(gòu)圖了;畫UI時(shí)除了Coding的區(qū)域,還需要增加右側(cè)的布局預(yù)覽;編譯時(shí),底部的監(jiān)視窗口用于觀察編譯速度,編譯錯(cuò)誤時(shí)分析原因;運(yùn)行時(shí)底部的Logcat用于看日志內(nèi)容。
熟悉項(xiàng)目文件結(jié)構(gòu)
如果你是接手一個(gè)現(xiàn)成的項(xiàng)目,執(zhí)行完git fetch
,導(dǎo)入整個(gè)項(xiàng)目,在擼起袖子干之前,不妨先熟悉整個(gè)項(xiàng)目的文件結(jié)構(gòu)。這有助于你后續(xù)工作中快速定位到對(duì)應(yīng)的位置,修改代碼。
項(xiàng)目中各種文件的存放位置一般遵循以下規(guī)則:
如果項(xiàng)目包含子模塊(Sub Module),以上規(guī)則同樣適用于各子模塊。
熟悉項(xiàng)目文件結(jié)構(gòu)的過程中,我們同樣可以試著回答以下問題:
Java層代碼主要使用的是Java還是Kotlin?
異步框架使用的是RxJava、Coroutines還是傳統(tǒng)的Handler、Executer?
有沒有使用Sub Module劃分模塊?代碼按照什么規(guī)則隔離分層?
Maven Dependencies有依賴哪些熱門組件?
有沒有使用Router?Dagger?AOP?插件化?
類似的還有很多。隨著經(jīng)驗(yàn)的積累,你所能提出的問題就越多,越有助于你與整個(gè)開發(fā)團(tuán)隊(duì)的節(jié)奏保持一致,避免寫出不符合團(tuán)隊(duì)風(fēng)格的代碼。
Gradle
Android的編譯構(gòu)建工具,也就是Gradle,它的語法基于Groovy,是一種DSL(Domain Specific Language)語言。它既可以用來寫構(gòu)建的各種配置(Maven依賴、本地Projects相互依賴、插件依賴),也可以編輯調(diào)整構(gòu)建的任務(wù)流程,亦或者用來寫一些簡(jiǎn)單的可執(zhí)行邏輯。
Gradle是一個(gè)很容易勸退新手的地方。隨著擴(kuò)張,一個(gè)項(xiàng)目的Gradle文件往往會(huì)變得愈發(fā)冗長(zhǎng)復(fù)雜,內(nèi)部充斥著各種依賴、執(zhí)行邏輯,讓人無法輕易理解。這里我們不妨先簡(jiǎn)單的了解下Gradle的一些基本概念,好在后續(xù)閱讀Gradle文件時(shí)有個(gè)大致的頭緒。
Gradle首先可以用于配置參數(shù)和一些依賴。例如上面的Gradle代碼,用于配置Android項(xiàng)目編譯的各種依賴項(xiàng)——Maven倉庫地址、編譯版本。下面是我將這些Gradle代碼類比成了Java代碼的形式,方便理解,它們等同于一系列的setter
和import:
其次,Gradle中也可以寫一些簡(jiǎn)單的可執(zhí)行邏輯。例如上面的給到的一個(gè)函數(shù),當(dāng)某個(gè)文件無法被找到時(shí),通過命令行去執(zhí)行一個(gè)python腳本。這個(gè)函數(shù)可以被其他Domain調(diào)用執(zhí)行。
最后,Gradle的構(gòu)建任務(wù)由兩個(gè)基本單元組合而成:
Project
Task
一個(gè)Android App項(xiàng)目至少擁有一個(gè)Project,一個(gè)Project中可以包含(1..n)個(gè)Tasks。它們相互之間的關(guān)系可以用下面這張草圖來描述:

Project是Gradle編譯執(zhí)行的交互接口。你可能沒有直接接觸過它,但你肯定見到過build.gradle
文件。一個(gè)build.gradle
文件就是對(duì)一個(gè)Project的定義和實(shí)現(xiàn)。項(xiàng)目中有幾個(gè)build.gradle文件,就代表了有幾個(gè)Project。其中,項(xiàng)目根目錄下的build.gradle
作為整個(gè)App編譯的入口。
Project也可以存在依賴關(guān)系。其中,項(xiàng)目根目錄下的settings.gradle
文件用于告知Gradle,這個(gè)App Project需要編譯哪些Projects。

而非根目錄下的Project(Android項(xiàng)目中稱作Module),它們相互之間亦可以存在依賴關(guān)系。它們的依賴關(guān)系直接定義在其build.gradle
的dependencies domain中
Task是Gradle編譯的最小單元。如它的名字一樣,Task為整個(gè)編譯過程拆分后的一個(gè)個(gè)單元“任務(wù)“。它會(huì)從上一個(gè)Task中獲取Context,做點(diǎn)什么,(可能)修改一些Context中的內(nèi)容,最后將Context傳遞給它的下一個(gè)Task。整個(gè)流程近似一條流水線(pipeline)一樣。
那么Task的執(zhí)行順序是如何決定的呢?這里引申出一個(gè)可能會(huì)令人困惑的點(diǎn):它們的執(zhí)行順序由它們的依賴關(guān)系決定的。不通于使用控制邏輯if-else
、switch-case
直接控制程序的執(zhí)行邏輯,Task間只能通過dependsOn
來決定它們的依賴關(guān)系,從而間接的控制它們的執(zhí)行邏輯。形如:
這樣Gradle的執(zhí)行順序就會(huì)是taskA → taskB
讓我們玩的稍微花一些:Task同樣可以一對(duì)多,或者多對(duì)一的依賴。
那么最終形成的依賴關(guān)系,和最重Gradle的執(zhí)行順序,大概是:

Task需要依賴于Project,所以定義Task和依賴關(guān)系,需要在build.gradle
中處理。
UI Components & Data Sources
Android開發(fā)(可能)大部分的工作都集中在將數(shù)據(jù)呈現(xiàn)在UI。自嘲高級(jí)UI工程師的同時(shí),UI與數(shù)據(jù)間的交互方式卻從來沒有停止進(jìn)化的腳步。

第一代交互方式。先在xml中繪制出UI的布局,然后在Activity
中渲染,最后通過findViewById
定位到需要操作的View
,通過手動(dòng)調(diào)用各種Setter和Callback來做到UI和數(shù)據(jù)的雙向綁定。

Databinding伴隨著MVVM模式的走紅成為了第二代交互方式的代名詞。我們可以在定義完UI對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)對(duì)象后,在xml中直接將它們綁定在對(duì)應(yīng)的UI控件上。編譯過程中,每個(gè)引入Databinding的xml都會(huì)自動(dòng)生成其對(duì)應(yīng)的Binding類(build/generated/data_binding_base_calss_source_out),其中有自動(dòng)生成的UI與數(shù)據(jù)的雙向綁定代碼。
可以說Databinding極大的簡(jiǎn)化了高級(jí)UI工程師們的工作量,并且跟易于后續(xù)的維護(hù)工作。你可以避免出現(xiàn)類似數(shù)據(jù)更新后,忘記手動(dòng)調(diào)用Setter方法,從而沒有刷新UI的Bug。

Google近期大力推廣的Compose有機(jī)會(huì)成為第三代交互方式。
Compose出現(xiàn)之前,Android的視圖是樹形結(jié)構(gòu)。更新視圖需要手動(dòng)操作樹形結(jié)構(gòu)中的節(jié)點(diǎn),有的情況下還需要調(diào)整樹形結(jié)構(gòu)本身(addView
、removeView
),官方稱其為“命令式視圖”。
Compose意在以聲明式UI來進(jìn)一步減少通過DataBinding實(shí)現(xiàn)響應(yīng)式UI的代價(jià)。舉個(gè)例子,通過DataBindingUI和數(shù)據(jù)的雙向綁定時(shí),一般有三個(gè)步驟:
Layout:畫UI布局
Compose:將一般數(shù)據(jù)組裝成
LiveData
包裹的可觀察數(shù)據(jù)Bind:在布局文件中將可觀察數(shù)據(jù)與View綁定
而Compose帶來的響應(yīng)式編程直接將這三個(gè)步驟平鋪在了一起,畫布局、綁定可觀察的數(shù)據(jù)、包裝數(shù)據(jù)這些工作可以混合在一起處理。
原先你可以直接構(gòu)建一個(gè)View
、ViewGroup
對(duì)象,添加到UI樹中,并且在運(yùn)行時(shí)可以隨時(shí)調(diào)整它的各種屬性,甚至隨時(shí)將它從UI樹中移除。
但是Compose中,你已經(jīng)不能這么干了。你無法直接接觸到各種View
對(duì)象,進(jìn)而無法調(diào)用它的各種方法,更別說隨意的從UI樹中移除。你只能調(diào)用各種UI Widget對(duì)應(yīng)的@Composble
靜態(tài)函數(shù)來聲明你要?jiǎng)?chuàng)建的布局或者UI組件,同時(shí)將布局或UI組件的屬性綁定到對(duì)應(yīng)的可觀察數(shù)據(jù)(State
),后續(xù)對(duì)UI的控制也只能通過更新State
來實(shí)現(xiàn)。
初步體驗(yàn)下來,Compose有一定的學(xué)習(xí)曲線,代碼整體風(fēng)格更偏向于前端,而對(duì)可觀察數(shù)據(jù)需要有更強(qiáng)的抽象能力。它同時(shí)將DataBinding的理念貫徹到底,直接杜絕了聲明UI后再直接操作UI的可能性。所有的UI刷新都是通過更新State
,或者更加靈活的冷流Flow
,最終由Compose框架決定是否需要更新UI,以及更新哪些部分的UI,以犧牲自由換取更高效率。
Third-part Dependencies

大到搭建一個(gè)App項(xiàng)目,小到完成一個(gè)小需求,這些工作都不是從0開始的。琳瑯滿目的第三方依賴庫能夠幫助你節(jié)約開發(fā)時(shí)間、提升開發(fā)質(zhì)量,從而將你大部分的精力集中在業(yè)務(wù)本身,畢竟你不是總有那么足夠的時(shí)間去造一個(gè)個(gè)輪子(多數(shù)時(shí)候造的還不那么好)。
使用第三方依賴庫的一些要注意的點(diǎn):
安裝包體積:只是為了使用一個(gè)很小的功能點(diǎn),卻要引入一個(gè)體積龐大的依賴
間接依賴沖突:第三方依賴庫A和B都間接依賴了C,但是依賴C的版本不同。編譯時(shí)產(chǎn)生沖突,或者可以編譯但是運(yùn)行時(shí)拋出異常
廢棄后帶來的問題:如果作者不再維護(hù)它了,Bug-fix和一些升級(jí)所帶來的適配沒有人來處理
遇到這些情況時(shí),你可能就得為之前的便利還一些技術(shù)債。fork一份源代碼做修改,或者不得不自己重新造一個(gè)輪子。
架構(gòu)、架構(gòu)模式、設(shè)計(jì)模式
這三個(gè)概念經(jīng)常會(huì)被混淆。從宏觀向微觀的順序來看:
架構(gòu):用于描述系統(tǒng)的組件棧、組件之間的層次和依賴關(guān)系,它只是一個(gè)草圖,所以我們沒有辦法通過只閱讀架構(gòu)圖來了解系統(tǒng)的細(xì)節(jié),或者進(jìn)行具體的實(shí)現(xiàn)
架構(gòu)模式:也就是我們常聽到的MVC、MVP、MVVM、MVI。它負(fù)責(zé)定義各個(gè)模塊的職責(zé),起到一個(gè)解耦的效果。同時(shí)它也會(huì)定義各個(gè)模塊間的通信方式,以及信息的流動(dòng)方向
設(shè)計(jì)模式:特指24種設(shè)計(jì)模式。人類的本質(zhì)是復(fù)讀機(jī),你所遇到的問題,絕大多數(shù)情況下別人也遇到過,設(shè)計(jì)模式就是前人留下的這些特定問題的優(yōu)解
所以回到Android開發(fā)者,一般情況下我們是不會(huì)接觸到架構(gòu),更多的時(shí)候是跟架構(gòu)模式、設(shè)計(jì)模式打交道。
我們?yōu)槭裁葱枰@些條條框框呢?《Designing Data-Intensive Applications》一書提出了我們耳熟能詳?shù)膬?yōu)秀代碼三要素:可靠、可拓展、可維護(hù)。我對(duì)這三點(diǎn)做了些自己的理解:
可靠:不容易出Bug
可拓展:不容易改出Bug
可維護(hù):別人不容易改出Bug
在這些條條框框的加持下,你的代碼能夠清晰的表現(xiàn)出你的思路和意圖。這樣不管是自己還是別人,后續(xù)閱讀代碼時(shí)能夠快速準(zhǔn)確的理解,并做出合理的修改。
設(shè)計(jì)模式
24種設(shè)計(jì)模式大部分人都閱讀過,但輪到自己寫時(shí)難免會(huì)抓瞎。這并不奇怪,能在實(shí)際工作中正確的使用其中幾種,就已經(jīng)算佼佼者了。比起全部知道但一個(gè)都不會(huì)用,這里我推薦掌握以下幾種模式:
裝飾模式
策略模式
狀態(tài)模式
代理模式
為什么會(huì)推薦這幾種?因?yàn)樵诮邮忠粋€(gè)項(xiàng)目時(shí),我們很容易遇到需要拓展原功能的場(chǎng)景。在你還不能完全了解項(xiàng)目全貌的時(shí)候,這幾種模式可以使你新業(yè)務(wù)的代碼與舊業(yè)務(wù)的代碼和諧共處。
同時(shí)推薦一個(gè)專門學(xué)習(xí)Android場(chǎng)景下設(shè)計(jì)模式的網(wǎng)站(https://www.kodeco.com/18409174-common-design-patterns-and-app-architectures-for-android#)。作者對(duì)每一種模式都做了適用場(chǎng)景的描述,輔以對(duì)應(yīng)的代碼和插圖,非常的用心。
架構(gòu)模式

不管是MVC、MVP、MVVM、MVI,都是一種劃分角色的體現(xiàn)。有了角色分工,大家才能各司其職,按照協(xié)議交流,避免相互干擾?;\統(tǒng)的看,架構(gòu)模式區(qū)劃分出三種角色:UI、ViewModel、Repo(sitory)。它們的屬性如下:
View負(fù)責(zé)UI維護(hù)
Repo負(fù)責(zé)數(shù)據(jù)維護(hù)
View和Repo不依賴其他角色
View和Repo可以被復(fù)用
大量的業(yè)務(wù)邏輯堆砌在ViewModel中
ViewModel依賴View和Repo
MVC


MVC應(yīng)該是最早提出的一種架構(gòu)模式,它將代碼分為這三個(gè)角色:
Model:數(shù)據(jù)維護(hù)
View:UI
Controller:處理數(shù)據(jù)、業(yè)務(wù)和UI之間的關(guān)系。一般由Fragment或Activity承擔(dān)
MVC是一種比較基礎(chǔ)的代碼隔離模式。它提出的View和Model角色,在后面的模式進(jìn)化中都保留了下來,Controller充當(dāng)它們的Adapter。三者之間沒有強(qiáng)制的隔離,也就是說,角色間兩兩可以直接調(diào)用,形成耦合關(guān)系。在后續(xù)遇到修改時(shí),不可避免的會(huì)導(dǎo)致依賴修改。同時(shí),充當(dāng)Controller角色的Fragment或Activity非常容易膨脹,演變出數(shù)千乃至數(shù)萬行代碼。
MVP


在MVC的基礎(chǔ)上演化出了MVP架構(gòu)模式,相較于MVC,它有三個(gè)明顯的變動(dòng):
Activity和Fragment不再代理Controller,專注于處理View。而原先Controller的任務(wù)全部交由專門的Presenter處理
使用接口定義View和Model。在接口定義不變的情況下,View和Model內(nèi)部實(shí)現(xiàn)可以自由調(diào)整,甚至可以將View和Model替換成接口相同的其他的實(shí)現(xiàn)對(duì)象,做到了復(fù)用
View與Model完全隔離,彼此間不知道對(duì)方的存在。所有的通信均通過Presenter代理
MVP真正實(shí)現(xiàn)了隔離、復(fù)用這些優(yōu)點(diǎn)。但由于Presenter代理了所有的通信任務(wù),接口會(huì)變得非常的龐雜。
MVVM


借助DataBinding等一系列組件,MVVM簡(jiǎn)化了原先需要手動(dòng)處理的雙向通信,只剩下View → ViewModel(響應(yīng)UI事件)和ViewModel → Repo(發(fā)起Fetch事件)兩處通信需要手動(dòng)處理。Repo和ViewModel的Reaction信息全部通過諸如LiveData
、RxJava
自動(dòng)反饋在可觀察數(shù)據(jù)中,從而降低MVP中出現(xiàn)的接口復(fù)雜度。
MVI


MVI在MVVM的基礎(chǔ)上,更加強(qiáng)調(diào)了數(shù)據(jù)與狀態(tài)間的轉(zhuǎn)換關(guān)系,從而弱化了ViewModel層的重要性。簡(jiǎn)單的說,如果數(shù)據(jù)流能直接轉(zhuǎn)換對(duì)應(yīng)成UI狀態(tài),那么View和Model將可以直接通信,不需要ViewModel層作為中間層中轉(zhuǎn)通信或者存儲(chǔ)中間數(shù)據(jù)。

總結(jié)下四種架構(gòu)模式的遞進(jìn)演變過程:
MVC實(shí)現(xiàn)了初級(jí)角色定義和代碼隔離
MVP在MVP的基礎(chǔ)上斷開了Model與View的直接交互能力
MVVM在MVP的基礎(chǔ)上簡(jiǎn)化了通信成本
MVI在MVVM的基礎(chǔ)上簡(jiǎn)化了ViewModel的邏輯
效率提升
規(guī)范的代碼能有效的提升閱讀效率,減少低級(jí)錯(cuò)誤。如何使得自己的代碼更加規(guī)范?這里有兩層含義:
使自己的代碼風(fēng)格貼近整個(gè)團(tuán)隊(duì)。一個(gè)成熟的團(tuán)隊(duì)基本上都形成了適合自己團(tuán)隊(duì)的代碼規(guī)范,這些規(guī)范包含Tab/4 spaces、中文Encode編碼格式、try-catch-finally Return規(guī)則等等??梢粤私夂笤贏ndroid Studio的設(shè)置中對(duì)齊
使用Android Studio自帶的Lint工具,或者一些第三方lint插件(比如detekt),對(duì)方法行數(shù)、單行字?jǐn)?shù)、函數(shù)復(fù)雜度、異常處理方式等作出規(guī)則限制,IDE標(biāo)黃或者直接編譯出錯(cuò)
同時(shí),熟悉Android Studio的常用快捷鍵,比如:
Format Code
Go to Line
Go to Class
Search Everywhere
Run
Rename Class/Variant
Find Usage
Navigate Back/Forward
平時(shí)留意一些別人推薦的Android Studio插件,比如:
模版輸入Live Template
簡(jiǎn)單的抓包插件OkHttp Profiler
ADB快捷方式ADB Idea
如果平時(shí)有一些日常重復(fù)執(zhí)行的工作,盡早將它們寫成腳本,比如更新設(shè)計(jì)資源、圖片壓縮、拉取翻譯等等。
類似Copilot和Tabnine之類的AI學(xué)習(xí)插件可以學(xué)習(xí)你的代碼風(fēng)格,以便作出更加符合你預(yù)期的代碼提示,甚至直接生成完整的格式代碼。在非生產(chǎn)環(huán)境下,如果機(jī)器性能夠用,也推薦多多使用。
Debug

模擬器是Debug時(shí)非常好的工具,它可以用于補(bǔ)充真機(jī)一些難以覆蓋的場(chǎng)景,比如:弱網(wǎng)絡(luò)、低電量、Mock GPS位置、Mock傳感器數(shù)據(jù)、運(yùn)行特定版本的系統(tǒng)ROM等。經(jīng)歷了早起幾乎不可用的時(shí)代,現(xiàn)在Android Studio自帶的模擬器已經(jīng)可以非常流暢的使用了。

Log是調(diào)試時(shí)幾乎不可能繞過的一個(gè)點(diǎn)。使用Log定位問題幾乎適用于所有的調(diào)試場(chǎng)景,但是Log使用時(shí)同樣有需要注意的點(diǎn):
Log是有性能開銷的,盡量少打不必要的Log,不要在循環(huán)和遞歸中輸出Log
Log主要集中在異常場(chǎng)景,用于排查問題時(shí)使用。Log單次輸出的內(nèi)容信息盡量完整:入?yún)?、錯(cuò)誤類型、調(diào)用堆棧等
選擇合理的日志等級(jí)
Debug:只有Debug的時(shí)候才需要看,生產(chǎn)環(huán)境不會(huì)輸出
Info:非錯(cuò)誤,正常流程的觸發(fā)
Warning:預(yù)期內(nèi)的異常,不會(huì)對(duì)使用造成影響或者影響較小
Error:預(yù)期外的異常,會(huì)對(duì)使用造成影響(關(guān)鍵業(yè)務(wù)不可用、crash等)
不要在Log中輸出敏感信息(密碼、Token、真實(shí)信息等)

斷點(diǎn)(Breakpoint)是另一種常用的調(diào)試手段,它可以在指定的位置掛起代碼的執(zhí)行,并做以下的事情:
查看成員變量?jī)?nèi)容
查看調(diào)用棧
通過Evaluate Expression臨時(shí)插入代碼執(zhí)行
斷點(diǎn)的使用場(chǎng)景存在一定的約束:
App啟動(dòng)時(shí)不適合斷點(diǎn)
多線程業(yè)務(wù)場(chǎng)景不適合斷點(diǎn)
主線程不適合斷點(diǎn)
調(diào)試Api時(shí),可以使用諸如Inspect、Charles、OkHttp Profiler等工具進(jìn)行抓包,這里不做過多贅述。
一個(gè)好的開發(fā)同樣得是一個(gè)好的測(cè)試,開發(fā)需要對(duì)自己的代碼負(fù)責(zé),而不是寄希望于其他人幫你兜底。這里枚舉了一些常用的單元測(cè)試框架及適用的場(chǎng)景:

感謝你看到這里。如果本文中大部分的內(nèi)容你已經(jīng)掌握,那么恭喜你已經(jīng)是一位合格的Android開發(fā)者了~