Android 系統穩定性 - ANR(三)

文章都爲原創,轉載請註明出處,未經允許而盜用者追究法律責任。
很久之前寫的了,留着有點浪費,共享之。
編寫者:李文棟

1.4 如何避免ANR
1.4.1 ANR發生在主線程,不要阻塞主線程

        Android應用程序的所有標準組件全部運行在一個單一的主線程中,在主線程中所做的任何耗時的操作都有可能造成ANR,因爲這些耗時的操作會使得主線程沒有機會處理用戶輸入事件或者廣播事件。
        因此在主線程中執行的任何函數所做的工作都應該儘可能的少,特別是對於Activity的生命週期函數來說。網絡和數據庫操作,以及諸如位圖變換的一些耗時的操作,都應該放在子線程中完成。主線程不需要等待子線程的執行,主線程應該創建一個與其綁定的Handler對象,子線程執行完畢後通過Handler通知主線程。
        創建子線程的方式有很多,Android中提供了很多相關的API,例如HandlerThread、AsyncTask、AsyncQueryHandler等,當然也可以創建簡單的線程或線程池。不過需要注意的是,不要製造太多的“野”線程,例如在Android原生代碼中經常會見到在某個函數中new了一個Thread對象,調用其start函數啓動後就不再管理了。筆者對這種寫法並不認同,這種寫法的優點是避免了子線程對某些對象的強引用,以免內存泄漏,但是反而有潛在的風險會造成“線程泄漏”,也就是說可能會多次執行相同的操作創建大量的子線程,而這些子線程很可能由於某種原因被阻塞而都無法正常退出,大量的線程本身就會佔用內存和CPU,搶佔臨界資源,而且執行的多是重複的操作。所以筆者建議將子線程“管理”起來,無論是用標誌位還是用成員變量,總之不要讓線程隨意的被創建,用有限數量的線程或線程池處理所有的請求,可以用Handler將請求隊列化,去除重複的請求減少資源浪費,同時應該在適當的時候(例如Activity銷燬時)考慮停止子線程,避免不必要的操作和內存泄漏。
        BroadcastReceiver通常是用來在後臺執行一些小型的、瑣碎的工作,例如保存程序設置。不要在BR中執行需要長時間運行的操作,這些操作應該放到Serivce中。另外,不要在BR中啓動一個Activity,因爲那樣會創建一個新的窗口,新窗口會搶奪屏幕焦點,用戶原先正在交互的窗口失去焦點後就不會再接收到輸入事件。新窗口的突然出現可能會讓用戶很詫異,或者也有可能出現由於舊窗口的層(Window的type屬性)比較高,新窗口沒能顯示,但是輸入事件又被新窗口搶奪的情況。如果在BR中有消息要提示用戶,可以考慮使用NotificationManager在狀態欄中顯示通知來達到目的。
1.4.2 消除停頓感
        通常人們感知界面有停頓感的時間需要100到200毫秒,所以爲了給用戶更好的體驗,在避免ANR的基礎上更進一步來消除停頓感,有以下幾個建議:
                如果應用程序正在後臺執行耗時工作,可以使用ProgressBar或者ProgressDialog來提示用戶工作進度;
                對於遊戲類的應用,應該使用子線程去做位置計算;
                如果應用程序的初始化過程比較耗時,可以在初始化時顯示一個過場動畫或者圖片,也可以先快速的顯示主界面然後再異步的加載初始化數據。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章