Android vitals 幫您解決應(yīng)用質(zhì)量問(wèn)題

對(duì)于應(yīng)用開(kāi)發(fā)者而言,衡量應(yīng)用成功最好的指標(biāo)就是開(kāi)心的用戶,而且是越多越好。達(dá)到這一目的的最佳途徑就是開(kāi)發(fā)一個(gè)好應(yīng)用,那么什么樣的應(yīng)用才能被稱作是 “好” 應(yīng)用呢?歸根結(jié)底就是兩件事:功能以及應(yīng)用質(zhì)量。前者取決于開(kāi)發(fā)者的創(chuàng)造力以及選用的商業(yè)模型;而后者則能夠被客觀測(cè)量及改善。

去年谷歌進(jìn)行的一項(xiàng)內(nèi)部調(diào)查顯示 Play Store 中超過(guò) 40% 的一星應(yīng)用存在穩(wěn)定性問(wèn)題。另一方面,對(duì)于性能卓越的應(yīng)用,人們打分和評(píng)論往往越來(lái)越好,這讓它們?cè)?Google Play 中的排名上升,下載量也隨之增加。不僅如此,用戶參與度也更高,而且愿意花更多的時(shí)間和金錢(qián)在這些應(yīng)用上。

因此,解決應(yīng)用穩(wěn)定性問(wèn)題能夠顯著影響到應(yīng)用成功與否。

通過(guò)對(duì)應(yīng)用質(zhì)量的客觀測(cè)量,開(kāi)發(fā)者能夠輕易發(fā)現(xiàn)應(yīng)用亟待解決的穩(wěn)定性問(wèn)題,為此我們?cè)?Google Play Console 添加了一款名為 Android vitals 的新板塊。借助 Android vitals,開(kāi)發(fā)者無(wú)須添加額外工具代碼或者庫(kù)就能了解應(yīng)用存在的性能及穩(wěn)定性問(wèn)題。當(dāng)應(yīng)用在大量設(shè)備上運(yùn)行時(shí),Android vitals 會(huì)收集與應(yīng)用性能相關(guān)的匿名數(shù)據(jù)。通過(guò)這種途徑獲得的信息量是其他方式無(wú)法匹及的,即使是硬件實(shí)驗(yàn)室測(cè)試也不行。

Android vitals 可以向開(kāi)發(fā)者發(fā)送以下三種警告:崩潰、應(yīng)用程序無(wú)法響應(yīng)以及渲染次數(shù)。這三種情況都會(huì)直接影響到用戶體驗(yàn)以及他們對(duì)應(yīng)用的評(píng)價(jià)。此外,用戶可能不會(huì)將 “異常耗電事件” 這類不良行為與您的應(yīng)用直接聯(lián)系起來(lái)。

這篇文章將探討其中以下兩個(gè)問(wèn)題:

1.?過(guò)度喚醒:過(guò)度喚醒會(huì)對(duì)電池壽命造成影響,而且在無(wú)法及時(shí)充電的情況下,可能導(dǎo)致用戶無(wú)法繼續(xù)使用設(shè)備。此類行為可能會(huì)讓用戶迅速卸載您的應(yīng)用;

2.?應(yīng)用程序無(wú)法響應(yīng) (ANR) 事件:當(dāng)應(yīng)用的用戶界面卡住時(shí)候,此類事件會(huì)被觸發(fā)。在界面凍結(jié)時(shí),若您的應(yīng)用在前臺(tái)運(yùn)行,會(huì)出現(xiàn)對(duì)話框提醒用戶 “關(guān)閉應(yīng)用” 或者 “等待響應(yīng)”。對(duì)用戶而言,此類行為和應(yīng)用崩潰一樣糟糕。他們可能不會(huì)馬上卸載您的應(yīng)用,但是如果 ANR 問(wèn)題一直不解決,就很有可能會(huì)尋找其它替代應(yīng)用。

過(guò)度喚醒

那么,什么是喚醒?什么時(shí)候又是喚醒 “過(guò)度” 呢?

為了延長(zhǎng)電池續(xù)航時(shí)間,屏幕關(guān)閉后,Android 設(shè)備會(huì)禁用主 CPU 內(nèi)核,進(jìn)入深度睡眠模式。除非用戶喚醒設(shè)備,設(shè)備最好可以盡可能長(zhǎng)地保持這種狀態(tài)。不過(guò),在發(fā)生某些事件的情況下,還是很有必要喚醒 CPU 并向用戶發(fā)出警告 —— 比如說(shuō),鬧鐘觸發(fā)或者收到新消息。開(kāi)發(fā)者可以通過(guò)喚醒鬧鐘 (wakeup alarm) 來(lái)處理此類警告,不過(guò)也不一定非要這么操作,在下文中會(huì)對(duì)此稍加解釋。到目前為止,喚醒看上去似乎是個(gè)不錯(cuò)的東西,讓重要事情能引起用戶注意,不過(guò)要是喚醒太多次就適得其反,電池壽命也會(huì)大打折扣。

Android vitals 如何顯示過(guò)度喚醒

Android vitals 能夠幫助開(kāi)發(fā)者了解自己的應(yīng)用是否存在喚醒次數(shù)太多的問(wèn)題。通過(guò)收集有關(guān)應(yīng)用行為的匿名數(shù)據(jù),Android vitals 可以顯示有多少比例的用戶在設(shè)備滿電之后,每小時(shí)經(jīng)歷 10 次以上的設(shè)備喚醒。關(guān)鍵就是看有沒(méi)有紅色的圖標(biāo)出現(xiàn),若圖標(biāo)出現(xiàn),則說(shuō)明應(yīng)用已經(jīng)越過(guò)了不良行為門(mén)檻,屬于 Google Play 中表現(xiàn)最次的一檔應(yīng)用,而您則須要想辦法改善應(yīng)用行為了。

除了喚醒鬧鐘,還有別的方法嗎?

開(kāi)發(fā)者主要是通過(guò) AlarmManager API 設(shè)定 RTC_WAKEUP 或 ELAPSED_REALTIME_WAKEUP 旗標(biāo),讓?xiě)?yīng)用在特定時(shí)間或者在某一時(shí)間間隔后喚醒設(shè)備。該功能須謹(jǐn)慎對(duì)待,僅在沒(méi)有其它更優(yōu)的任務(wù)調(diào)度和通知機(jī)制的情況下才可使用。在使用喚醒鬧鐘的時(shí)候,您需要考慮以下幾點(diǎn):

>>若您需要顯示信息以響應(yīng)來(lái)自網(wǎng)絡(luò)的數(shù)據(jù),考慮通過(guò)使用 Firebase Cloud Messaging 等工具來(lái)實(shí)現(xiàn)消息推送。利用該機(jī)制而不是定期輪詢新數(shù)據(jù),您的應(yīng)用會(huì)僅在需要時(shí)才被喚醒。

>> 如果您無(wú)法使用消息推送并依賴定期輪詢,考慮使用 JobScheduler 或者 Firebase JobDispatcher (或者使用 SyncManager 來(lái)處理賬戶數(shù)據(jù))。它們的 API 等級(jí)比 AlarmManager 高,而且在智能任務(wù)調(diào)度方面具備以下優(yōu)點(diǎn):

-- 批量操作:批量操作任務(wù)而不是多次喚醒系統(tǒng)進(jìn)行操作,這使設(shè)備能更長(zhǎng)時(shí)間處于睡眠狀態(tài)。

-- 標(biāo)準(zhǔn):您可以明確任務(wù)運(yùn)行須滿足的具體標(biāo)準(zhǔn),如網(wǎng)絡(luò)可用性或者電池充電狀態(tài)。設(shè)定標(biāo)準(zhǔn)能夠避免喚醒設(shè)備以及不必要的應(yīng)用運(yùn)行。

-- 持續(xù)性以及自動(dòng)退避 —— 繼續(xù)執(zhí)行任務(wù) (即使在重啟后) 并且在失敗的情況能自動(dòng)重試。

-- 低耗電模式 (doze) 兼容性 —— 僅在低耗電模式或者應(yīng)用待機(jī)模式未設(shè)定任何限制的情況下,任務(wù)才能運(yùn)行。

當(dāng)且僅當(dāng)消息推送以及任務(wù)調(diào)度對(duì)您的任務(wù)不適用時(shí),您才可以利用 AlarmManager 設(shè)定喚醒鬧鐘。換個(gè)角度來(lái)說(shuō)就是,僅當(dāng)您想要在特定時(shí)間觸發(fā)鬧鐘,不考慮網(wǎng)絡(luò)以及其它情況,喚醒鬧鐘才是必要的。

當(dāng) Android vitals 顯示過(guò)度喚醒時(shí),您應(yīng)采取何種對(duì)策?

為了解決過(guò)度喚醒問(wèn)題,您須要確認(rèn)應(yīng)用在什么地方設(shè)定了喚醒鬧鐘,然后降低這些鬧鐘的觸發(fā)頻率。

那么如何查看應(yīng)用在哪些地方設(shè)了喚醒鬧鐘呢?您可以打開(kāi) Android Studio 中的 AlarmManager 類,右擊 RTC_WAKEUP 或者 ELAPSED_REALTIME_WAKEUP 域,選擇 "Find Usages (查找使用)",然后您就能看到項(xiàng)目中所有使用到此類旗標(biāo)的事件了。仔細(xì)查看每一種事件,然后考慮能否改用更為智能的任務(wù)調(diào)度機(jī)制。

您也可以將 Find Usage (查找使用) 中的范圍設(shè)定為 “Project and libraries (項(xiàng)目和庫(kù))”,查看依賴項(xiàng)是否在使用 AlarmManager API。如果確實(shí)在使用,那么您應(yīng)該考慮使用別的庫(kù),或者向依賴項(xiàng)開(kāi)發(fā)人員報(bào)告錯(cuò)誤。

若您認(rèn)為使用喚醒鬧鐘無(wú)法避免,那么如果您的鬧鐘標(biāo)簽滿足以下要求,Play Console 可以提供更好的分析數(shù)據(jù):

>>在鬧鐘標(biāo)簽中包含包、類或者方法名稱。這也可以幫助您輕松確定在源中的哪些地方設(shè)定了鬧鐘;

>>不要使用 Class#getName() 給鬧鐘命名,因?yàn)?Proguard 會(huì)對(duì)此產(chǎn)生混淆。請(qǐng)使用硬編碼字符串;

>>不要向鬧鐘標(biāo)簽添加計(jì)數(shù)器或者其它唯一標(biāo)識(shí)符,因?yàn)橄到y(tǒng)可能會(huì)貴去掉這類標(biāo)簽,而且無(wú)法將它們計(jì)入有效數(shù)據(jù)內(nèi)。

應(yīng)用程序無(wú)法響應(yīng)


那么,什么是應(yīng)用程序無(wú)法響應(yīng) (以下簡(jiǎn)稱為ANR)?它又是怎么影響到用戶的呢?

對(duì)用戶而言,ANR 就是指當(dāng)他們?cè)噲D與應(yīng)用進(jìn)行交互時(shí),但界面卡住的事件。界面卡屏幾秒后,會(huì)出現(xiàn)對(duì)話框讓用戶選擇繼續(xù)等待或者強(qiáng)行停止應(yīng)用。

從開(kāi)發(fā)者的角度來(lái)看,ANR 則是指應(yīng)用運(yùn)行的操作耗時(shí)過(guò)久,如磁盤(pán)或網(wǎng)絡(luò) I/O,導(dǎo)致主線程阻塞。主線程 (有時(shí)候也被稱為 UI 線程) 主要負(fù)責(zé)響應(yīng)用戶事件以及每秒刷新 60 次屏幕。因此很關(guān)鍵的一點(diǎn)將任何可能延時(shí)主線程工作的操作轉(zhuǎn)到后臺(tái)線程。

Android vitals 如何顯示應(yīng)用程序無(wú)法響應(yīng)?

Android vitals 能收集并利用應(yīng)用 ANR 事件的匿名數(shù)據(jù),提供多個(gè)級(jí)別的 ANR 具體報(bào)告。主界面上概述了您應(yīng)用中 ARN 活動(dòng)的概覽信息,顯示用戶至少經(jīng)歷一次 ANR 事件的日對(duì)話比重,并且提供前一天以及前 30 天的情況的單獨(dú)報(bào)告。同時(shí)也提供了不良行為門(mén)檻。

打開(kāi)詳情界面,即 ANR 比率頁(yè)面,您能夠了解不同時(shí)間的 ANR 具體比例,以及針對(duì)不同應(yīng)用版本、活動(dòng)名稱、ANR 類別、以及 Android 系統(tǒng)下的 ANR 情況。您可以就 APK 版本代碼、支持設(shè)備、OS 版本以及時(shí)間,篩選查看這些數(shù)據(jù)。

應(yīng)用程序無(wú)法響應(yīng)常見(jiàn)原因

如上文所述,當(dāng)應(yīng)用進(jìn)程影響到主線程時(shí),ANR 事件會(huì)被觸發(fā),而導(dǎo)致這種阻塞現(xiàn)象的原因各有不一,較為常見(jiàn)的有:

>>在主線程上執(zhí)行磁盤(pán)或者網(wǎng)絡(luò) I/O。這是迄今為止導(dǎo)致 ANR 的最常見(jiàn)原因。雖然大部分開(kāi)發(fā)者認(rèn)同不應(yīng)該在主線程上進(jìn)行讀寫(xiě)磁盤(pán)或者網(wǎng)絡(luò),但是有時(shí)候我們就是忍不住這么做。在理想情況下,從磁盤(pán)上讀取幾個(gè)字節(jié)的數(shù)據(jù)并不會(huì)引發(fā) ANR,但是這絕對(duì)不是什么好主意。如果用戶的設(shè)備閃存很慢,如果其它同時(shí)進(jìn)行讀寫(xiě)的應(yīng)用已經(jīng)對(duì)設(shè)備造成了很大壓力,而您的應(yīng)用還在排隊(duì)等著運(yùn)行 “快速” 讀取操作, 這樣真的不夠明智,所以千萬(wàn)別在主線程運(yùn)行 I/O;

>>在主線程上運(yùn)行長(zhǎng)計(jì)算。那么內(nèi)存計(jì)算又是怎么一回事呢?訪問(wèn)時(shí)間長(zhǎng)并不會(huì)對(duì)內(nèi)存造成影響,較小的操作應(yīng)該也沒(méi)什么問(wèn)題。但是如果您開(kāi)始循環(huán)運(yùn)行復(fù)雜計(jì)算并且處理大數(shù)據(jù)集,主線程就很容易發(fā)生阻塞了。您可以考慮重新調(diào)整百萬(wàn)像素大圖像的體積,或者在解析大 HTML 文本塊后,再將文本顯示到 TextView 中??偟膩?lái)說(shuō),還是讓?xiě)?yīng)用在后臺(tái)運(yùn)行此類操作比較合適;

>>向主線程另一進(jìn)程同步調(diào)用 binder:與磁盤(pán)或網(wǎng)絡(luò)操作相似,在線程間進(jìn)行阻塞調(diào)用時(shí),程序執(zhí)行會(huì)被轉(zhuǎn)移到您無(wú)法控制的地方。如果說(shuō)其它進(jìn)程忙碌,該怎么辦?如果須要訪問(wèn)磁盤(pán)或者網(wǎng)絡(luò)以響應(yīng)您的請(qǐng)求,又該怎么辦?此外,數(shù)據(jù)在轉(zhuǎn)移到其它進(jìn)程前,須要經(jīng)過(guò)打包 (parcel) 與解包 (unparcel) 兩個(gè)步驟,會(huì)消耗不少時(shí)間。因此,還是建議從后臺(tái)線程進(jìn)行進(jìn)程間調(diào)用;

>>使用同步:即使您將復(fù)雜操作轉(zhuǎn)移到后臺(tái)線程運(yùn)行,依舊須要與主線程溝通以顯示計(jì)算結(jié)果。多線程編程不容易,并且在使用同步鎖的時(shí)候,很難保證不出現(xiàn)阻塞執(zhí)行。在最糟糕的情況下,可能會(huì)出現(xiàn)死鎖問(wèn)題,即不同線程相互卡死。最好不要自己設(shè)計(jì)同步,建議使用專門(mén)的解決方案,比如說(shuō) Handler,將不可變數(shù)據(jù)從后臺(tái)線程傳回主線程。

如何檢測(cè)應(yīng)用程序無(wú)法響應(yīng)原因

尋找觸發(fā) ANR 的原因不容易,我們拿 URL 類舉個(gè)例子:

1. 您想看到 URL#equals (判斷兩個(gè) URL 是否相同的方法) 阻塞線程嗎?SharedPreferences 又怎么處理呢?

2. 如果您是在后臺(tái)讀取數(shù)值的話,您能在前臺(tái)調(diào)用 getSharedPreferences 嗎?

這兩種情況都很可能導(dǎo)致長(zhǎng)時(shí)間阻塞操作。幸好我們有 StrictMode,不用再自己瞎猜是什么原因?qū)е?ARN 了。在調(diào)試構(gòu)建的時(shí)候,您可以使用這個(gè)工具捕捉主線程上的意外磁盤(pán)或網(wǎng)絡(luò)訪問(wèn)。

您可以在應(yīng)用中使用 StrictMode#setThreadPolicy,自定義檢查項(xiàng),包括磁盤(pán)和網(wǎng)絡(luò) I/O 以及您通過(guò) StrictMode#noteSlowCall 在應(yīng)用中觸發(fā)的慢調(diào)用。同時(shí),您也可以自己選擇讓 StrictMode 通過(guò)何種方式告知已檢測(cè)到阻塞調(diào)用:應(yīng)用崩潰、日志記錄還是顯示對(duì)話框?您可參看 ThreadPolicy.Builder class 獲取進(jìn)一步信息。

一旦您消除主線程上的阻塞調(diào)用,請(qǐng)記得再上傳應(yīng)用至 Play Store 前,關(guān)閉 StrictMode。

解決過(guò)度喚醒以及 ANR 問(wèn)題能夠提升應(yīng)用質(zhì)量及穩(wěn)定性,提高應(yīng)用評(píng)分,獲取更多好評(píng),最終增加下載量。使用 Android vitals 讓您輕松快速地了解應(yīng)用中亟待解決的問(wèn)題。發(fā)現(xiàn)并解決代碼中的這些問(wèn)題可能并不容易,但是您可以利用工具和技術(shù)有效地完成工作。

點(diǎn)擊這里您可查看Android?和?Google Play?相關(guān)內(nèi)容信息

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容