Android DDMS:終極 Android 控制台指南
已發表: 2022-03-11開發是一項棘手的業務。 目標不斷發展,新技術和領域定期出現,新工具不時出現,語言在似乎受到管理的破壞中發生變化。
儘管如此,即使有所有這些變化,基本規則仍然保持不變。 這些基本規則中最重要的一條是,要創建真正出色的軟件,您必須深入、持續和詳細地檢查您的執行系統。 診斷、調試和分析是有時在這種情況下使用的術語,但規則更深入。 一流的開發人員確實“感覺”了他的系統。 他知道什麼會導致塊等待更多內存釋放,什麼會將其線程運行到 CPU 飢餓狀態,哪些操作將導致大量 I/O 或網絡訪問,因此會減慢其整個操作。
真的沒有辦法解決。 您可能是一個非常聰明的開發人員,編寫了很棒的代碼,但是,除非您不具備上述技能,即能夠監控和研究系統運行時行為的細節,否則您在交付真正一流的代碼方面仍然會失敗應用程序。
事實上,在獲得一些經驗之後,你會發現一整類“代碼病”,這可以追溯到忽略了自省規則:簡單地說,編寫代碼(有時是智能代碼)而沒有持續監控其在實際平台上的影響.
Android 中的 DDMS:我自省的首選武器
對我們來說幸運的是,Android 社區已經設法提供了這麼多一流的內省工具。 Facebook 的 Stetho 是最好的,AT&T 的 ARO(“應用程序資源優化器”)有點老,但仍然是一流的,可能是最好的網絡監控控制台,而 LeakCanary 採取了一種更有限的方法來集中註意力(並且在它)在運行時內存洩漏檢測庫上。 長話短說,那裡不乏 Android 調試工具。
儘管如此,皇冠上的鑽石,在需要提取有關應用程序運行時行為的關鍵、準確和格式良好的數據時值得信賴的內省工具仍然是 Android Studio 中的舊版 Dalvik 調試監視器服務器 (DDMS),它自從 Eclipse Android 插件時代以來,我們就一直在使用(可惜沒有被這麼多團隊使用)。
DDMS 在 Android 開發中有多重要? 好吧,作為一個經驗不足的 Android 開發人員,知道我現在對 DDMS 和移動應用程序監控的一般了解是 5 到 6 年前,這將為我省去很多麻煩和調試之夜。
問題是 DDMS 非常容易掌握!
當然,與任何其他軟件工具一樣,正確使用它的很大一部分都帶有經驗。 你需要磨練你的專業技能一段時間,直到你真正擅長運行時性能監控。 但即使在幾個小時內,讀完這篇文章後說,如果你按照我的建議並將它們應用到你的下一個應用程序中,結果將是驚人的! 即使是複雜的系統,分析和調整也不是那麼難。 它也可以很有趣!
經常被問到關於新手和大師級移動開發人員之間的區別的問題。 掌握 Android 中的 DDMS(或者一般而言,應用程序分析和自省功能)就是這樣的主要區別之一。
注意:成為一流開發人員的主要部分是使用您所在域中可用的最佳庫。 在之前的 Toptal 文章中,我列出了一些可用於 Android 的最佳開發人員庫。 從某種意義上說,這篇文章是“庫”文章的續集,涵蓋了眾多 Android 工具之一。 不用說,如果您的目標是提高您的 Android 開發人員技能,請立即閱讀!
Android Studio 中的 DDMS 快速指南
現在,事不宜遲,讓我們現在深入了解 DDMS,這是終極的 Android 開發人員工具之一。
在權衡努力與收益時,可能沒有其他工具可以提高您的應用程序的質量並幫助您找到它可能包含的真正混亂和難以捉摸的錯誤。 但是,由於某種原因(懶惰,有人嗎?),很多團隊沒有使用 DDMS。
讓我們從 DDMS 的速成課程開始:
可以通過Studio > Tools > Android > Android Device Monitor訪問 DDMS,然後單擊菜單上的 DDMS 按鈕。 您也可以在上面板中放置一個快捷方式圖標(我願意)。
打開後,您將看到以下內容:
左側面板允許選擇設備/應用程序,右側控制台為您提供多個視圖,每個視圖都位於其自己的選項卡中,每個視圖都顯示您的應用程序的特定視圖。
Dalvik Debug Monitor Server 提供的主要服務有:
- 應用內存使用統計(總堆和對象分配統計)
- 應用線程統計
- 設備屏幕截圖
- 設備文件瀏覽器
- 來電和短信欺騙
- 位置數據欺騙
- 日誌貓
要獲取您的應用程序使用的當前堆內存值,只需執行以下操作:
- 連接運行您的應用程序的設備
- 單擊更新堆按鈕以啟用堆統計信息收集
- 打開堆選項卡
- 點擊“Cause GC”強制GC運行。 只有在這樣的運行之後,堆數據收集才會開始
- 保持選項卡打開,繼續處理您的應用程序,並定期重新單擊“Cause GC”以刷新堆統計數據
最後一行可能需要額外的解釋。 內存使用量是其中動態比初始值更重要的分析值之一。 對於大多數應用程序,我們不會太在意初始堆使用值。 我們將非常關心這個值的進展,因為它將為我們提供一個明確的指示,即等待移動開發人員的真正噩夢之一——Android 內存洩漏:
我對堆統計模塊的使用很簡單; 作為開發應用程序生命週期的一部分,在引入可能影響堆使用的更改後,我將激活模塊,“Cause GC”以初始化統計數據收集,激活(通常不止一次)我的應用程序的堆密集型位置,並定期“導致 GC”刷新。 如果堆使用量不斷增長,我的手上有內存洩漏,我需要解決它(詳細說明如何 - 下面)。 如果不是,並且無論實際堆大小如何,我都很好。
如果檢測到內存洩漏,我將使用的下一個工具是對象分配跟踪器。 讓我們看看它可以為 Android 中的內存管理做些什麼。
對象分配跟踪器
簡而言之,分配跟踪器將為您提供所需的信息,以確定誰是當前堆大小的“罪魁禍首”。 該模塊將實時告訴您分配命令來自哪些線程和方法,這對於 Android 中的內存分析非常有用。
要開始跟踪,請執行以下操作:
- 像以前一樣選擇相關的設備/進程
- 切換到 Allocation Tracker 選項卡,然後單擊 Start Tracking 開始。
- 從這裡開始,將跟踪所有新的分配
- 單擊“獲取分配”以獲取所有最新分配的列表視圖(自上次“開始”以來的最新)
- 要找出分配機構是誰,請單擊列表中的特定行
現在,根據我自己的經驗,在您的應用程序上執行分配密集型操作,然後單擊“獲取分配”以查看分配計數器通常應該以直接的方式引導您找到洩漏; 有時,當洩漏是非線性的(即,時不時發生)或者當您的應用程序包含多個可能無法工作的洩漏時。 在這種情況下,我還沒有遇到很多,您將需要手動創建轉儲 HPROF 文件並對其進行分析。 本文不會深入介紹內存分析和 Android 內存管理。 請參閱此處了解一些線索。
線程信息控制台:輕鬆使用 Android CPU
任何開發人員都知道,執行邏輯的同步路徑被分組到線程中,每個線程在您的應用程序中構成一個串行執行流。 從字面上看,所有應用程序都使用多個執行線程。 其中一些使用數十個。
使用線程時對潛在問題的全面檢查超出了本文的範圍。 然後讓我們專注於一個問題,即線程飢餓,這是您訪問線程信息控制台的主要問題。
在所有移動應用程序中,不同的線程都會爭奪 CPU 時間。 根本沒有足夠的人可以四處走動。 如果出於某種原因,一個或多個線程無法獲得所需的執行時間,會發生什麼情況? 通常是壞事。 系統不會像您計劃的那樣運行,這總是一個壞主意。 這個問題的潛在原因可能是設置低優先級,同時執行的其他線程將自己設置為過高的優先級,在同步監視器上花費很長時間等等。 眾所周知,僅通過代碼審查很難檢測到所有這些。
Android DDMS 線程控制台來救援!
當您進入線程視圖時,您將看到一個由線程記錄組成的列表,每個記錄包含線程的名稱和 ID,以及兩個稱為 utime 和 stime 的額外計數器。 Utime 衡量線程執行用戶代碼所花費的總時間(想想你的函數和第三方庫),而 stime 衡量花費在系統代碼上的總時間(睡眠、同步、系統調用——很多)。 第一個——utime——通常對我們來說更有趣,儘管我能想到的問題大多會通過時間計數器來體現。
好的,我們的代碼正在運行,包括幾個線程,我們希望確保我們所有的線程都能獲得它們的 CPU 時間份額。 為此,我們首先讓系統運行一段時間,然後打開線程選項卡並開始尋找“特殊”的 utime 值。 零當然可以代表一個問題——線程實際上沒有 CPU 時間和 CPU 利用率。 但是過高的值可能代表同一問題的不同方面:即優先級高到導致其他線程餓死的線程。
請注意,對於一種類型的線程,零或接近零的 utime 值並不表示真正的問題。 這些是 I/O 綁定線程,主要執行網絡或磁盤(或數據庫)訪問的線程。 這些線程應該花費大部分時間等待數據到達或阻塞掛起的系統調用,這些操作都不會增加 utime 計數器。 了解你的線程!
提示:切勿使用線程的默認名稱。 它沒有任何意義,您通常無法在 DDMS 視圖中檢測到它。 相反,每當創建一個線程或從線程池中獲取它時,通過為其分配一個不言自明的名稱來開始您的交互。 這將使您的生活比調試/分析您的系統更容易。 我通常會在應用程序名稱前加上 Android 生成的線程和我自己的代碼生成的線程,例如:MyApp-server-connector、MyApp-db-interactor 等。

提示:線程的優先級表示(粗略地說)調度程序將授予的 CPU 時間量。 分配給工作線程的優先級對應用程序的整體性能和“流暢性”至關重要,在許多情況下,這可能是快速行為與顛簸緩慢行為之間的區別。 這裡的規則很簡單:Android 分配的默認優先級,即 NORMAL=5,幾乎總是不是您想要使用的優先級。 相反,對於大多數工作線程,您希望對整體 CPU 使用率的影響更小。 為此,在線程啟動時,將其優先級設置為較小的值,我通常使用優先級=3。
網絡統計控制台
網絡統計是關於允許您以合理的人類可讀方式監控應用程序的傳入和傳出通信通道。
網絡圖表中的 y 軸代表以 KB/秒為單位測量的傳輸傳輸速度,而 x 軸代表以秒為單位的經過時間。 因此,為了快速估計傳輸的大小,請嘗試估計相關尖峰的面積。 一段時間後,這變得相當容易。
請注意,進入此控制台後,您需要單擊上方的“啟用”按鈕才能開始顯示網絡測量。
在網絡控制台成熟到現在的水平之前,開發人員通常不得不求助於使用嗅探器應用程序(有些仍然這樣做)來獲取類似的信息。
這個控制台的偉大之處在於它可視化了主要的電池消耗行為之一 - 正在進行的小數據包大小的通信。 正如你們許多人所知,使您的應用程序耗電的不是它所做的五分鐘密集網絡,而是長時間的短時間重複網絡,例如,為了保持活動、診斷或狀態更新。
一旦檢測到這樣的模式,並且網絡控制台的可視數據包顯示使其變得如此簡單,立即考慮批處理。 我可以將多個小傳輸批量成一個大傳輸嗎? 這種變化對電池的影響勢必會將應用程序從電池消耗者轉移到表現良好的類別!
提示:切勿將圖像按原樣加載到內存中。 這是等待發生的內存不足崩潰。 相反,執行按比例縮小的加載,甚至更好的是,使用第三方庫為您管理縮放。
儘管您很少使用此信息,但請注意,DDMS 依賴於 Android 調試橋 (ADB) 堆棧來將數據傳回/傳出設備。 如果 DDMS 無法顯示您的應用程序,或在 DDMS 會話中間凍結,您最好的辦法是打開控制台並輸入:
adb devices
確保您的設備可以訪問並獲得亞行的授權。 如果不是這種情況,在許多情況下,重新啟動本地 ADB 服務器應該可以解決問題:
adb kill-server adb devices # restarts the adb server and displays all detected devices
如果您仍然遇到問題並且您的應用程序安裝在物理設備上,請嘗試斷開所有模擬器實例的連接。 為什麼? 因為 DDMS 將自己連接到物理設備設備和仿真器實例,所以默認為後者。
現實生活中的 DDMS 用法示例:應用程序停止(不是崩潰,只是停止)。 用戶立即衝到附近的工作站,連接到 USB,並在線程視圖中打開 DDMS 以找出線程堆棧 » 失敗線程 » 堆棧跟踪 - 在我的情況下,由於同步死鎖,一旦檢測到,通過切換很容易解決。
提示:如果 Android 分配給您的應用程序的標準 RAM 內存不夠,例如媒體密集型應用程序可能會發生這種情況,請注意,您可以通過提高 _ largeHeap清單標誌在大多數設備上獲得大約 15-20% 的額外內存:https://developer.android.com/guide/topics/manifest/application-element.html_
Android DDMS 中的設備狀態仿真
通常,移動應用程序不是線性結構。 相反,他們部署了意識策略,使他們能夠監控設備狀態的變化並做出反應。 例如,應用程序可以收聽來電或短信,可以根據網絡狀態重新調整其狀態,並可以跟踪設備位置的變化並做出反應。
後者的一個簡單示例是 GPS 應用程序。 我們大多數人不開發這樣的應用程序(唉,市場不夠大......)但在許多情況下,我們確實部署了與位置相關的邏輯,無論是用戶當前位置的簡單地圖視圖,路線跟踪,或位置敏感的數據顯示。
測試這種狀態敏感條件是出了名的複雜,有時甚至比編寫實際代碼還要復雜。 如果您有帶 SIM 卡的物理設備,您當然可以發出和接聽電話和短信。 更改設備的電話狀態要困難得多,但仍然可以完成。 更改測試位置可能會比較棘手,但可以選擇帶著筆記本電腦在城裡閒逛……
但是——我們將如何處理模擬器實例? 我們如何測試它們的這些變化?
DDMS 再次進行救援。 DDMS 更強大但經常被忽視的特性之一是它能夠將模擬事件發布(“欺騙”)到正在運行的模擬器實例中。 DDMS 可以從特定號碼向模擬器發出呼叫、發送 SMS、更改電話狀態數據等等。
一旦進入仿真器,所有這些欺騙事件將不再與“真實”事件區分開來,即好像被底層硬件傳感器接收到一樣。 具體來說,您的所有相關應用程序的接收器都將以與接收到真實呼叫/短信時相同的方式激活。
激活電話狀態和操作相當簡單:
要測試您的應用程序的低網絡連接情況(您應該在任何以網絡為中心的應用程序中),請轉到電話狀態部分並將速度和延遲值設置為所需的值。 我通常將 GPRS 值作為模擬低連接性的有效方法,但您可以隨意設置自己的值。
要模擬電話或短信,請轉到電話操作部分,設置原始電話號碼,如果需要添加短信,然後開火。 當您為來自國外的呼叫設置專用代碼路由並希望在預算範圍內對其進行測試時,此工具特別有效。
當涉及到模擬一個新位置時,事情變得更加有趣。
如果您的目標只是為您的模擬器實例設置一個新位置,請選擇手動,設置所需的緯度/經度值,然後點擊發送。
但是,如果不是設置一個固定位置,而是希望您的應用程序通過預先設置的路線——例如,在用戶從一個城市到另一個城市旅行時檢查其行為,該怎麼辦? 這樣的測試對於任何支持地圖的應用程序以及其他根據用戶位置設置數據窗口的位置敏感應用程序都具有很大的價值。 在這裡,您將希望看到以不同速度移動的位置將使顯示的數據窗口保持最新。
為此,我們將使用一種稱為 KML 的特殊格式,該格式專為與 Google 地球一起使用而開發,將路線或路徑表示為空間中的一組連接點,可以由支持 GPS 的設備使用。
GPX 是 DDMS 支持的另一種路徑格式。 出於所有實際目的,當用於移動位置欺騙時,這兩者應該被認為是可互換的。
現在讓我們來看看在模擬器中設置模擬路由的各個階段。
- 創建路線。 到目前為止,最簡單的方法是使用谷歌地圖方向選項設置適當的起點和終點。
路線顯示在地圖上後,轉到地址行並複制 URL
使用剪貼板中的 URL,轉到 GPS Visualizer,將其粘貼到“提供 URL”文本框中,然後單擊轉換按鈕:
並單擊下載生成的 GPX 文件(名稱有點亂,例如 20170520030103-22192-data.gpx)
- 回到 DDMS 位置控制,打開 GPX 選項卡,單擊加載 GPX 並選擇新下載的文件
- 我們完成了! 您現在可以通過單擊後退和前進按鈕在不同的路線位置之間導航,或者單擊播放按鈕以設定的速度自動通過路線。
您不需要創建自己的路線。 從 OpenStreetMap 等站點下載大量路線(參見“GPS 軌跡”部分)。
最後,請注意,與較舊的 DDMS 版本不同的是,較舊的 DDMS 版本可以輕而易舉地加載路徑文件,而較新的版本在加載特定路徑時可能需要一些試驗和錯誤。
例如,DDMS 似乎只支持 GPX 1.1。 新的 GPX 版本可能需要一些手動調整。
此外,不再支持 GPX 航路點格式。 相反,使用 GPX Track 格式:
<trk> <name /> <cmt /> <trkseg> <trkpt lat="27.0512" lon="-80.4324"> <ele>0</ele> <time>2017-02-02T08:01:41Z</time> </trkpt> </trkseg> </trk>
調試 Android:每週一小時會有所作為!
理論夠了! 現在是時候進行一些練習了。 我建議,假設您是一名 Android 開發人員,從您的下一個項目開始,您將每週只花一個小時來通過 DDMS 對您的應用程序的性能進行內省。
您會對這將為您提供的大量質量信息(即可用於立即改善您的應用程序狀態的信息)感到驚訝!
Android DDMS,正如我在新手開發人員中一次又一次地看到的那樣,是一個可以大大提高開發人員能力的工具,只要掌握並正確使用它。 一旦 Android 開發人員充分利用 DDMS 在 Android 開發中的潛力,他們交付一流系統的能力就會提高一兩個檔次。 因此,留出幾個小時用好 DDMS 聽起來是一項明智的投資,因為它可以大大提高 Android 的性能和效率。
成為聰明人之一。 用它。