源地址:${android-sdk-windows}/docs/guide/practices/design/responsiveness.html
你寫的代碼也許能夠通過世界上所有的效能測試,但是當使用者使用你的這個應用的時候卻可能會發狂。因為,你的應用程式的使用者響應性太差了,比如用起來不夠流暢,在關鍵的時刻掛起或者失去響應,或者花費了太多的時間用來處理使用者的輸入。在android系統中,當應用程式在一段時間內沒有響應的時候,系統會檢測到此種情況,並且向使用者顯示一個對話方塊,這個對話方塊被稱為“ANR”對話方塊(Application Not Responding)。這個時候使用者可以選擇繼續等待程式運行,也可以選擇強制關閉此應用。但是,如果每次使用這個應用都要看到這個對話方塊並且選擇操作,顯然使用者不會很爽。所以,在你的設計中,添加對應用響應性的考慮,以避免系統彈出這個ANR對話方塊,就顯得非常重要。
通常情況下,如果應用不能夠響應使用者的輸入,系統就會顯示這個ANR對話方塊。比如,如果一個應用因為IO操作而阻塞(通常是訪問網路),那麼應用的主線程就不能處理使用者輸入的事件。一段時間後,系統推測出該應用已經“僵死”,那麼就會顯示這個ANR對話方塊來給使用者關閉這個應用的選擇。類似的,如果你的應用花費大量的時間在記憶體中構建一個複雜的資料結構,或者可能是計算遊戲中的下一個移動點,系統此時就會認為你的程式已經掛起。這種情況下,首先要確認你的演算法的效能足夠好,但是即使的最高效率的代碼,運行起來也是需要時間的。針對上面提到的兩種情況,強烈推薦的方法是建立一個子線程,在子線程中完成這些耗時的操作。這樣的話,由於使用者介面的事件迴圈是在主線程中啟動並執行,故可以保持主線程一直在運行而避免系統認為你的程式已經"僵死"。由於這些線程一般情況下是通過類來完成的,因此,可以將應用的響應問題認為是類層級的問題,與此對應的是,效能問題一般是方法層級的。本文描述了android系統是如何判斷一個應用無響應的,並且給出了提高應用響應性的指南。
What Triggers ANR?(什麼觸發了ANR?)在android中,系統是通過 Activity Manager 和 Window Manager這兩個系統層級的服務來監控應用的響應性的。當系統檢測的某個應用出現下面某種情況時,就會顯示這個ANR對話方塊:1. 對使用者輸入事件(比如按鍵,觸控螢幕幕)在5秒之內沒有響應;2. 一個BroadcastReceiver在10秒內沒有完成處理。
How to Avoid ANR(如何避免ANR)上面給出了ANR的定義,現在讓我們看一下為什麼android應用會出現ANR以及如何在你的程式中避免ANR。android應用一般是整體的在一個單線程(主線程)中運行,這意味著你應用中任何在主線程中執行的需要耗費很長時間的東西都會導致ANR,因為你的應用沒有機會處理使用者輸入事件或者廣播訊息。因此,在你的程式主線程中啟動並執行每一個方法都應該做儘可能少的工作。特別的,Activities在主要的生命週期方法比如OnCreate()或者OnResume()中也應該做盡量少的工作。可能會長時間啟動並執行操作比如網路或者資料庫操作,或者耗費大量計算的操作比如重新計算bitmap的大小等,這些盡量在子線程中完成(或者,對於資料庫操作,可以考慮使用非同步請求)。但這並不意味著在子線程完成運行之前你的主線程應該阻塞或者調用Thread.wait() or Thread.sleep()。主線程應該提供一個Handler來供子線程運行完畢時回傳資訊,而不是阻塞自己來等待子線程完成。採用上述方法來設計你的應用可以保證你的應用的響應性,從而避免因為5秒使用者事件沒響應逾時而導致的ANR對話方塊。對於顯示介面的其他線程也應該遵從上述實踐,因為它們同樣也受這個逾時規則約束。你可以使用android.os.StrictMode這個工具來協助找到你程式中不小心引入的潛在耗時的操作比如資料庫和網路操作。具體使用方法可以參見android.os.StrictMode這個類的使用說明。IntentReceiver執行時間的特殊約束說明它們應該做的一些在後台啟動並執行,小的,離散的工作,比如儲存配置資訊,註冊一個Notification等。所以,和在主線程中調用的方法一樣,應用應該避免在BroadcastReceivers中執行一些潛在的耗時的操作/計算。但是,當要響應一個耗時的廣播訊息(broadcast)時,你的應用應該啟動一個Service,而不是在子線程中完成這些大量的任務,因為BroadcastReceiver的聲明周期很短。順便說一句,你應該避免在一個Intent Receiver中啟動一個Activity,因為這樣的話會產生一個新的螢幕從而讓使用者當前啟動並執行程式失去焦點。如果你的應用在響應一個Intent broadcast時需要顯示一些資訊給使用者,你可以考慮使用訊息管理器(Notification Manager)。
Reinforcing Responsiveness(加強響應性)一般情況下,100-200毫秒是使用者能夠感覺到該應用有延遲的閾值。基於此,這裡是一些能夠使你的應用避免ANR並且看起來響應性還不錯的小竅門:-->如果你的應用在幕後處理以響應使用者輸入,向使用者顯示當前啟動並執行進度,可以考慮使用ProgressBar或者ProgressDialog。-->特別的針對遊戲,在子線程中計算位置移動;-->如果你的應用有一個耗時的初始化步驟,那麼考慮使用一個啟動畫面,或者先快速的顯示出主視圖,然後非同步載入資料資訊。無論哪種情況,你都應該暗示使用者應用程式正在操作,避免使使用者認為程式已經僵死。