Android应用程序设计策略
一个成功的Android应用程序往往提供一个突出的用户体验。当Android团队构建了一个有着健壮核心的系统后,大多数的用户体验将来源于用户和应用程序之间的的交互。显著的用户体验体现在三个核心特征上,即快速、响应、无缝。当然,每一个平台都曾经有过类似的三种性质。尽管如此,每个平台实现这些特性的方式也有所不同。下面将会简单地介绍在Android平台下面你的应用程序将如何达到这些要求。
(1)快速(Fast)
基于Android平台的设备一定是嵌入式设备,它不仅仅是一部电话,还是一个小型的手持电脑。在编写Android程序时不仅要时刻考虑执行的效率,还要考虑电池的续航能力。一般来说,高效的代码意味着最小的内存占用,意味着紧凑的风格,意味着避免了因为某种语言和编码习惯对性能的影响。
如何判断一个系统的合理性,这里有两个基本的原则:
不要做不是必须要做的事情;
尽可能地节省内存的使用。
(2)响应(Responsive)
在Android中,程序的响应性被活动管理器(ActivityManager)和窗口管理器(WindowManager)这两个系统服务所监视。当出现下列情况时,Android会认为该程序无响应:
5s内没有响应用户输入事件(如键盘输入);
一个意图接收器执行10s还没有完成。
在正常情况下,Android程序会完全的在一个单线程里运行。这意味着,任何应用程序的执行在主线程里超过一段时间就会弹出ANR(ApplicationNoResponse)的对话框,因为应用程序没有机会去处理用户输入和意图广播操作。
因此,任何主线程的方法都不能做很复杂的处理,特别是Activity对象在它的关键生命周期函数里不能处理太多,例如onCreate()和onResume()。那些潜在的需要很长时间运行的操作需要在另外的子线程中完成,例如网络或数据库操作,都是计算量很大的操作,如重新计算Bitmap图形大小(或者在数据库操作时,使用的是异步请求)。虽然如此,但这并不意味着主线程应该阻塞去等待子线程的完成,也不是去调用Thread.wait()或Thread.leep()。相反地,主线程应该提供一个Handler给子线程去返回完成信息。通过这种方式来设计应用程序,会使主线程仍然能够响应输入事件而避免由于5s无响应而产生ANR对话框。其他的显示用户界面的线程也是同样的道理,它们同样要在相同的时限之内做出响应。
这种在意图接收器(IntentReciever)上执行的特殊时间限制,强调那些小的少量处理应该按照规矩,例如保存一个设置或者寄存一个通告。因此,在调用主线程其他方法时,应用程序应该避免意图接收器(IntentReceiver)中潜在的长时间运行操作和运算。但是不是通过子线程来解决(因为IntentReceiver的生命周期很短),如果在相应一个特有的广播时段存在潜在的长时间运行的操作,你的应用程序应该开启一个服务(Service)。值得注意的是,你应该避免在一个IntentReceiver上开始一个活动(Activity),因为它将会产生一个新的屏幕去取代用户正在使用的屏幕。如果应用程序在一个意图广播(IntentBroadcast)响应中有什么东西要提示用户,开发者应该使用通知管理
器(NotificationManager)。
一般来说,100~200ms是用户在应用程序中能够感知到的极限。正如可以采取一些措施避免ANR,也可以采取一些措施增强程序的响应性。
如果应用程序正在后台运行并响应用户输入,说明进程正在创建,进度条(ProgressBar)和进度对话框(ProgressDialog)在这里很有作用。
如果是游戏编程,应该在一个子线程里做位移运算。
如果应用程序有一个比较耗时的初始化过程,可以考虑显示一个开场动画或者尽可能快地显示主窗口然后异步的填充其他的部分。
以上其中任意一种方法,都可以让用户感觉不到应用程序的停止。
(3)无缝性(Seamless)
系统设计将多个应用程序视为一种松耦合组件的联合。开发者在设计程序与程序或程序与系统之间交互时,需要完整地封装,无缝地和其他应用程序结合,设计高质量的应用程序。
不要丢失数据。
在开发应用程序时,始终应该考虑到Android是一个移动的平台。任何Activity(如有人给你打电话)在运行自己Activity时都有可能会突然弹出来,这将会调用onSaveInstanceState()和onPause()方法,很有可能终止当前进程。
如果用户正在编辑数据时,其他的Activity出现了,当前程序可能因为被终止而丢失一些数据。当然如果事先保存了数据就不会丢失。Android的编程思路也是这样:那些接收或编辑输入的Android程序应该重载onSaveInstanceState()方法,把程序的当前状态保存下来。当第二次访问该程序时,就会恢复数据。
一个使用这的经典例子就是邮件程序。如果用户正在编辑一个信件,这时外面一个Activity出现了,那么程序应该自动的把当前邮件保存到草稿本中。
使用内容提供器(ContentProvider)保护原始数据。
Android处理数据的方法是:创建一个内容提供器(ContentProvider),通过一个深思熟虑的可维护的API把程序数据提供给其他的应用程序。使用一个内容提供器就好像嵌入了一个Java的接口到两片代码之间,让它们能够相互交流。这意味着,你可以改变你内部的形式而不用修改ContentProvider暴露的接口,并且这不会影响应用程序的执行。
不要打断正在说话的用户。
如果用户正在运行一个程序(如正在打电话),他肯定不想受到其他程序干扰,除了需要从当前Activity获得用户输入的Activity外。这就是说,不要从运行在后台的意图接收器(IntentReceiver)或服务(Service)中调用startActivity(),这样做会打断任何当前运行的应用程序,就会使用户很不舒服。这样的活动(Activity)变成了一个'键盘强盗',它会把一些用户原本准备给前一个活动(Activity)的输入截取过来。
Android平台没有直接从后台运行活动(Activity),而是使用通知管理器(NotificationAnager)去设置通知消息。这将会在状态栏中显示,用户有空时就会单击它,看看程序需要什么东西。