2011年5月3日

Android Designing for Seamlessness

Designing for Seamlessness

Even if your application is fast and responsive, certain design decisions can still cause problems for users — because of unplanned interactions with other applications or dialogs, inadvertent(沒有注意) loss of data, unintended blocking, and so on. To avoid these problems, it helps to understand the context in which your applications run and the system interactions that can affect your application. In short, you should strive(努力) to develop an application that interacts seamlessly with the system and with other applications.
A common seamlessness problem is when an application's background process — for example, a service or broadcast receiver — pops up a dialog in response to some event. This may seem like harmless behavior, especially when you are building and testing your application in isolation, on the emulator. However, when your application is run on an actual device, your application may not have user focus at the time your background process displays the dialog. So it could end up that your application would display it's dialog behind the active application, or it could take focus from the current application and display the dialog in front of whatever the user was doing (such as dialing a phone call, for example). That behavior would not work for your application or for the user.
(當後段的程式想要提示訊息時,使用Notification不要使用其他(dialog…)讓後台的service, broadcast去中斷當前使用者)
To avoid these problems, your application should use the proper system facility(合適的技巧) for notifying the user — the Notification classes. Using notifications, your application can signal the user that an event has taken place, by displaying an icon in the status bar rather than taking focus and interrupting the user.
Another example of a seamlessness problem is when an activity inadvertently loses state or user data because it doesn't correctly implement the onPause() and other lifecycle methods. Or, if your application exposes data intended to be used by other applications, you should expose it via a ContentProvider, rather than (for example) doing so through a world-readable raw file or database.
(注意你的程式資料遺失,程式可能會在onPause()回來後資料遺失,注意Activity的生命週期,並且不要嘗試使用暴露資料的方式去讓多個應用程式互通資料,最好的方式是使用ContentProvider或是使用資料庫設計)
What those examples have in common is that they involve cooperating nicely with the system and other applications. The Android system is designed to treat applications as a sort of federation of loosely-coupled components, rather than chunks of black-box code. This allows you as the developer to view the entire system as just an even-larger federation of these components. This benefits you by allowing you to integrate cleanly and seamlessly with other applications, and so you should design your own code to return the favor.
(這些常見的問題其實都是發生在同一件事情上,就是多個應用程式之間的合作,由多個程式組成一個程式的聯盟,巧妙的運用這個技巧可以讓系統更佳完整,這也是Andorid設計的目的)
This document discusses common seamlessness problems and how to avoid them.

Don't Drop Data (不要丟棄系統資料)

Always keep in mind that Android is a mobile platform. It may seem obvious to say it, but it's important to remember that another Activity (such as the "Incoming Phone Call" app) can pop up over your own Activity at any moment. This will fire the onSaveInstanceState() and onPause() methods, and will likely result in your application being killed.
(Android是移動平台上的系統,所以很多時候可能會突然跳出其他視窗(例如來電),導致當前程式的暫停(onPause),這個必需要注意一點,我們要記得儲存(onSaveInstanceState)當前城市的狀態,以便在程式恢復時可以繼續執行,因為有時候這樣的事件會造成原應用程式被刪除)
If the user was editing data in your application when the other Activity appeared, your application will likely lose that data when your application is killed. Unless, of course, you save the work in progress first. The "Android Way" is to do just that: Android applications that accept or edit input should override the onSaveInstanceState() method and save their state in some appropriate fashion. When the user revisits the application, she should be able to retrieve her data.
(我們必須使用onSaveInstanceState()來儲存我們的資料)
A classic example of a good use of this behavior is a mail application. If the user was composing an email when another Activity started up, the application should save the in-process email as a draft.
(編寫郵件時,突然來電,我們必須幫使用者儲存郵件資料到寄件夾)

Don't Expose Raw Data (不要暴露資料)

If you wouldn't walk down the street in your underwear, neither should your data. While it's possible to expose certain kinds of application to the world to read, this is usually not the best idea. Exposing raw data requires other applications to understand your data format; if you change that format, you'll break any other applications that aren't similarly updated.
(我們把資料暴露給外部程式使用,這是一個不好的點子,當如果我們的資料格式改變了,則其它程式就無法繼續支持,導致崩潰)
The "Android Way" is to create a ContentProvider to expose your data to other applications via a clean, well-thought-out, and maintainable API. Using a ContentProvider is much like inserting a Java language interface to split up and componentize two tightly-coupled pieces of code. This means you'll be able to modify the internal format of your data without changing the interface exposed by the ContentProvider, and this without affecting other applications.
(Android我們如果要讓不同程式間溝通彼此資料,最好的方式是使用Android中的ContentProvider)

Don't Interrupt the User (不要中斷使用者)

If the user is running an application (such as the Phone application during a call) it's a pretty safe bet he did it on purpose. That's why you should avoid spawning activities except in direct response to user input from the current Activity.
(使用者在使用他的應用程式,這是自然而然的因為他想用才會去打開,所以我們要避免其他的應用中斷了使用者)
That is, don't call startActivity() from BroadcastReceivers or Services running in the background. Doing so will interrupt whatever application is currently running, and result in an annoyed user. Perhaps even worse, your Activity may become a "keystroke bandit" and receive some of the input the user was in the middle of providing to the previous Activity. Depending on what your application does, this could be bad news.
(因此我們要避免在Service,BroadcastReceivers使用)startActivity()啟用其他的應用)
Instead of spawning Activity UIs directly from the background, you should instead use the NotificationManager to set Notifications. These will appear in the status bar, and the user can then click on them at his leisure, to see what your application has to show him.
(我們因該使用Notification來提示使用者,再狀態欄中點擊開啟相應的方法)
(Note that all this doesn't apply to cases where your own Activity is already in the foreground: in that case, the user expects to see your next Activity in response to input.)

Got a Lot to Do? Do it in a Thread (把大量處理交給其他執行緒)

If your application needs to perform some expensive or long-running computation, you should probably move it to a thread. This will prevent the dreaded "Application Not Responding" dialog from being displayed to the user, with the ultimate result being the fiery demise of your application.
(如果程式嘗試去操作一些昂貴或是長時間的計算時,我們就將這些工作交給Thread操作,這樣可以避免當前程式無法回應,降低使用者的愉快 )
By default, all code in an Activity as well as all its Views run in the same thread. This is the same thread that also handles UI events. For example, when the user presses a key, a key-down event is added to the Activity's main thread's queue. The event handler system needs to dequeue and handle that event quickly; if it doesn't, the system concludes after a few seconds that the application is hung and offers to kill it for the user.
(在預設,所有的UI都會執行在主程序中,我們做的任何事件都會丟到handler中的task queue中,系統必須快速的將其計算結束,如果某個taskqueue中持續太久,這將會跳出訊息被使用者中止)
If you have long-running code, running it inline in your Activity will run it on the event handler thread, effectively blocking the event handler. This will delay input processing, and result in the ANR dialogs. To avoid this, move your computations to a thread. This Design for Responsiveness document discusses how to do that..
(避免這些把這些程式碼丟到Thread上執行吧,方法參閱 Design for Responsiveness)

Don't Overload a Single Activity Screen (別讓單一Activity做太多事情)

Any application worth using will probably have several different screens. When designing the screens of your UI, be sure to make use of multiple Activity object instances.
(當設計你的UI時,讓你的應用程式擁有許多不同的畫面是很值得的,千萬別把一堆UI塞在同一個視窗)
Depending on your development background, you may interpret an Activity as similar to something like a Java Applet, in that it is the entry point for your application. However, that's not quite accurate: where an Applet subclass is the single entry point for a Java Applet, an Activity should be thought of as one of potentially several entry points to your application. The only difference between your "main" Activity and any others you might have is that the "main" one just happens to be the only one that expressed an interest in the "android.intent.action.MAIN" action in your AndroidManifest..xml file.
So, when designing your application, think of your application as a federation of Activity(Activity聯盟) objects. This will make your code a lot more maintainable in the long run, and as a nice side effect also plays nicely with Android's application history and "backstack" model.
(記得使用聯盟式的設計,這樣可以讓我們的程式設計更具彈性,且容易修改)

Extend System Themes (擴展系統的主題)

When it comes to the look-and-feel of the user interface, it's important to blend in nicely. Users are jarred by applications which contrast with the user interface they've come to expect. When designing your UIs, you should try and avoid rolling your own as much as possible. Instead, use a Theme. You can override or extend those parts of the theme that you need to, but at least you're starting from the same UI base as all the other applications. For all the details, read Applying Styles and Themes.
(使用者使用程式的第一眼就是界面,所以介面是非常重要的,因此我們必須設計一個很容易更改的介面,使用主題它可以讓你很容易地擴展、覆蓋當前的主題,詳細資料可以參考Applying Styles and Themes)

Design Your UI to Work with Multiple Screen Resolutions(設計你的UI在各種解析度)

Different Android-powered devices will support different screen resolutions. Some will even be able to change resolutions on the fly, such as by switching to landscape mode. It's important to make sure your layouts and drawables are flexible enough to display properly on a variety of device screens.
(應用程式的layout,圖片能夠自己調適大小,這個是很重要的)
Fortunately, this is very easy to do. In brief, what you must do is provide different versions of your artwork (if you use any) for the key resolutions, and then design your layout to accommodate various dimensions. (For example, avoid using hard-coded positions and instead use relative layouts.) If you do that much, the system handles the rest, and your application looks great on any device.
(很幸運的,這很容易達成,我們在配置布局時,盡量避免使用固定,改而使用相對,例如relative layout,fill_partent….)

Assume the Network is Slow (必須假設網路是很慢的)

Android devices will come with a variety of network-connectivity options. All will have some data-access provision, though some will be faster than others. The lowest common denominator, however, is GPRS, the non-3G data service for GSM networks. Even 3G-capable devices will spend lots of time on non-3G networks, so slow networks will remain a reality for quite a long time to come.
That's why you should always code your applications to minimize network accesses and bandwidth. You can't assume the network is fast, so you should always plan for it to be slow. If your users happen to be on faster networks, then that's great — their experience will only improve. You want to avoid the inverse case though: applications that are usable some of the time, but frustratingly slow the rest based on where the user is at any given moment are likely to be unpopular.
One potential gotcha here is that it's very easy to fall into this trap if you're using the emulator, since the emulator uses your desktop computer's network connection. That's almost guaranteed to be much faster than a cell network, so you'll want to change the settings on the emulator that simulate slower network speeds. You can do this in Eclipse, in the "Emulator Settings" tab of your launch configuration or via a command-line option when starting the emulator.
(模擬器上的網路是與PC連結的,這會造成網路很快假象,我們可以使用命令行設定,模擬實際上的網路速率)

Don't Assume Touchscreen or Keyboard (不假定鍵盤形式)

Android will support a variety of handset form-factors. That's a fancy way of saying that some Android devices will have full "QWERTY" keyboards, while others will have 40-key, 12-key, or even other key configurations. Similarly, some devices will have touch-screens, but many won't.
When building your applications, keep that in mind. Don't make assumptions about specific keyboard layouts -- unless, of course, you're really interested in restricting your application so that it can only be used on those devices.
(很多的程序或設備上,他們的鍵盤按鍵有多種的形式,因此我們在設計程式時千萬不要預先假定他們的布局)

Do Conserve the Device Battery (能夠保證電力正常消耗)

A mobile device isn't very mobile if it's constantly plugged into the wall. Mobile devices are battery-powered, and the longer we can make that battery last on a charge, the happier everyone is — especially the user. Two of the biggest consumers of battery power are the processor, and the radio; that's why it's important to write your applications to do as little work as possible, and use the network as infrequently as possible.
Minimizing the amount of processor time your application uses really comes down to writing efficient code. To minimize the power drain from using the radio, be sure to handle error conditions gracefully, and only fetch what you need. For example, don't constantly retry a network operation if one failed. If it failed once, it's likely because the user has no reception, so it's probably going to fail again if you try right away; all you'll do is waste battery power.
Users are pretty smart: if your program is power-hungry, you can count on them noticing. The only thing you can be sure of at that point is that your program won't stay installed very long.
(我們因該寫有效率的程式,一個大量耗電的程式,很明顯的,不會在使用者手機存活太久)

沒有留言:

ShareThis