2011年5月3日

Android Designing for Responsiveness

Designing for Responsiveness
(設計良好的響應性)
In this document
2.     How to Avoid ANR












Figure 1. An ANR dialog displayed to the user.
It's possible to write code that wins every performance test in the world, but still sends users in a fiery rage when they try to use the application. These are the applications that aren't responsive enough — the ones that feel sluggish(停滯), hang or freeze for significant periods, or take too long to process input.
(寫好一個具良好響應性的應用是很重要的,我們應該避免在任何時候程式停滯、凍結、或是花很長的時間做某件事情造成使用者等待)
In Android, the system guards against applications that are insufficiently responsive for a period of time by displaying a dialog to the user, called the Application Not Responding (ANR) dialog, shown at right in Figure 1. The user can choose to let the application continue, but the user won't appreciate having to act on this dialog every time he or she uses your application. It's critical to design responsiveness into your application, so that the system never has cause to display an ANR dialog to the user.
(當某個應用程式的響應時間超時時,Android系統會顯示一個提示視窗,Application Not Responding(ANR),告知使用者是否讓程序繼續執行,但使用者通常對這個提示是很不領情的,所以我們因該要避免系統顯示這個視窗,思路不是叫你去停用這個視窗,而是讓你的系統有更好的響應性)
Generally, the system displays an ANR if an application cannot respond to user input. For example, if an application blocks on some I/O operation (frequently a network access), then the main application thread won't be able to process incoming user input events. After a time, the system concludes that the application is frozen, and displays the ANR to give the user the option to kill it.
(通常系統會提示一個視窗,當應用程式無法響應給使用者時)
Similarly, if your application spends too much time building an elaborate in-memory structure, or perhaps computing the next move in a game, the system will conclude that your application has hung. It's always important to make sure these computations are efficient using the techniques above, but even the most efficient code still takes time to run.
In both of these cases, the recommended approach is to create a child thread and do most of your work there. This keeps the main thread (which drives the user interface event loop) running and prevents the system from concluding that your code has frozen. Since such threading usually is accomplished at the class level, you can think of responsiveness as a class problem. (Compare this with basic performance, which was described above as a method-level concern.)
(解決這樣的問題,我們可以在子線程中進行這些事情,讓主現成不會呈現呆滯、凍結狀態)

This document describes how the Android system determines whether an application is not responding and provides guidelines for ensuring that your application stays responsive.
(這篇文章描述Android系統如何去判定一個應用程式它沒有響應,並且如何提供方式讓你的程序繼續持續響應)
What Triggers ANR? (為何會觸發ANR)
In Android, application responsiveness is monitored by the Activity Manager and Window Manager system services. Android will display the ANR dialog for a particular application when it detects one of the following conditions:
(Android系統中,每個Activity都是由ActivityManager,WindowManager系統服務來管理,當我們的應用出現下面狀況時,就會跳出ANR視窗)
·         No response to an input event (e.g. key press, screen touch) within 5 seconds
·         BroadcastReceiver hasn't finished executing within 10 seconds

·         在五秒內沒有任何的響應(鍵盤按鍵、螢幕觸碰)
·         廣播接收在10秒內沒有完成該工作
How to Avoid ANR (如何避免ANR)
Given the above definition for ANR, let's examine why this can occur in Android applications and how best to structure your application to avoid ANR.
Android applications normally run entirely on a single (i.e. main) thread. This means that anything your application is doing in the main thread that takes a long time to complete can trigger the ANR dialog because your application is not giving itself a chance to handle the input event or Intent broadcast.
(Android應用程式正常情況下都會執行在主程序中,也就意味著當你的主程序在做一件長時間的事情,就會觸發ANR,因為你的程式已經沒有任何機會去處理輸入與啟動廣播)
Therefore any method that runs in the main thread should do as little work as possible. In particular, Activities should do as little as possible to set up in key life-cycle methods such asonCreate() and onResume(). Potentially long running operations such as network or database operations, or computationally expensive calculations such as resizing bitmaps should be done in a child thread (or in the case of databases operations, via an asynchronous request).
(不要把網路、資料庫以及高度運算的程式放在你的onCreate以及onResume)
However, this does not mean that your main thread should block while waiting for the child thread to complete — nor should you call Thread.wait() or Thread.sleep().
(這不是意味著我們要把主線程停止去等待子線程完成進度,更不是呼叫Thread.wait() Thread.sleep()方法)
+++++++++++++++++++++++++++↓這裡是重點↓+++++++++++++++++++++++++++
Instead of blocking while waiting for a child thread to complete, your main thread should provide a Handler for child threads to post back to upon completion.
(我們應該讓我們的主線程提供一個handler給子線程,讓子線程完成操作時可以返回,這邊也就是為什麼子線程無法直接操作UI,因為他們必須有個橋樑handler)
Designing your application in this way will allow your main thread to remain responsive to input and thus avoid ANR dialogs caused by the 5 second input event timeout. These same practices should be followed for any other threads that display UI, as they are also subject to the same timeouts.
You can use StrictMode (嚴格的模式)to help find potentially(潛在) long running operations such as network or database operations that you might accidentally be doing your main thread.
(我們可以參考StrictMode來發現潛在的響應問題)
The specific constraint(限制) on IntentReceiver execution time emphasizes what they were meant to do: small, discrete amounts of work in the background such as saving a setting or registering a Notification. So as with other methods called in the main thread, applications should avoid potentially long-running operations or calculations in BroadcastReceivers.
(IntentReceiver的執行表示它是正在執行的!!應用程式因該避免把太長的操作或計算放在BroadcastReceivers,畢竟它只有10秒的時間!!)
But instead of doing intensive tasks via child threads (as the life of a BroadcastReceiver is short), your application should start a Service if a potentially long running action needs to be taken in response to an Intent broadcast. As a side note, you should also avoid starting an Activity from an Intent Receiver
(我們應該要使用Service,如果有長時間的執行出現在broadcast,而且我們要避免在Receiver中啟動一個Acitivy畢竟只有10)
, as it will spawn a new screen that will steal focus from whatever application the user is currently has running. If your application has something to show the user in response to an Intent broadcast, it should do so using the Notification Manager.
(如果真的要在廣播中提示使用者一些消息,那請你使用Notification)

Reinforcing Responsiveness (增強響應能力)
Generally, 100 to 200ms is the threshold beyond which users will perceive lag (or lack of "snappiness," if you will) in an application. As such, here are some additional tips beyond what you should do to avoid ANR that will help make your application seem responsive to users.
(通常響應時間不要超過0.2秒使用者是不會感覺到LAG的,下面提供一些方法替代ANR)
·         If your application is doing work in the background in response to user input, show that progress is being made (ProgressBar and ProgressDialog are useful for this).
(使用進度條提示)
·         For games specifically, do calculations for moves in a child thread.
(遊戲的移動交給子線程)
·         If your application has a time-consuming initial setup phase, consider showing a splash screen or rendering the main view as quickly as possible and filling in the information asynchronously.
(如果需要大量時間做初始化,那在起始畫面做些讓使用者分心的事情,讀取條、動畫等)
·         In either case, you should indicate somehow that progress is being made, lest the user perceive that the application is frozen.

TIP: 製造一些假象讓使用者不覺得系統呆滯、凍結。

沒有留言:

ShareThis