ITEEDU

构建响应性的应用程序

在这篇文章里面,我们将要涉及到Android是如何判断一个程序没响应的(会调用ANR),ANR产生的原因和确保你的应用程序能够响应的方法。除了在 ”构建高效Android程序“一文外,这里有一系列的实例教我们如何确保我们的用户界面能够响应,但是,在深入研究这些之前,这里有一个屏幕不能响应团出来的对话框:

当好的应用程序变坏

在Android中,程序的响应性被Activity Manager和Window ManagerIn这两个系统服务所监视。当出现下列情况是,Android会认为该程序无响应:

  • 5秒内没有响应用户输入事件(如键盘输入)
  • 一个BroadcastReceiver 执行十秒还没有完成

如何避免ANR

鉴于上面对ANR的解说,让我们测试一下为什么这些会发生在我们的应用程序中以及为防止ANR如何构建你的应用程序。

在正常情况下,Android程序会完全的在一个单线程里运行。这就意味着,任何你应用程序的执行在你的主线程里超过一段时间就会导致弹出ANR对话框,因为你的应用程序没有机会去处理用户输入和broadcast操作。

因此,任何主线程的方法都不能做很复杂的处理。特别是Activity对象在它的关键生命周期函数里面不能处理太多,例如onCreate()onResume()。那些潜在的需要很长时间运行的操作需要在另外的子线程中完成,例如网络或数据库操作,计算量很大的操作,如重新计算bitmap图形大小(或者在数据库操作时,使用的是异步请求)。虽然如此,但这并不意味着你的主线程应该阻塞去等待子线程的完成,也不是调用 Thread.wait()Thread.sleep()。相反的,你的主线程应该提供一个Handler给子线程去返回完成信息。通过这种方式来设计你的程序,会使你的主线程任然能够响应输入事件而避免由于5秒无响应而产生ANR对话框。其他的显示用户界面的线程也是同样的道理,它们同样要在相同的时限之内。

这种在IntentReciever执行上的特殊限制时间强调那些小的少量的处理应该按照规矩来,例如保存一个设置或者寄存一个通告。因此,在调用主线程其他方法的时候,应用程序应该去避免在BroadcastReceivers中潜在的长时间运行操作和运算。但是不是通过子线程来解决(因为BroadcastReceiver 的生命周期很短),如果在相应一个特有的广播时存在潜在的长时间运行的操作,你的应用程序开启一个服务(Service)。值得注意的是,你应该避免在一个Intent Receiver上开始一个 Activity,因为它将会产生一个新的屏幕去取代用户正在实用的屏幕。如果你的应用程序在一个Intent broadcast响应中有什么东西要给提示给用户,你应该使用 Notification Manager。

加强响应性

一般来说,100到200毫秒是用户在应用程序中能够感知到的极限。正如我们可以采取一些措施避免ANR,我们也可以采取一些措施增强程序的响应性。

  • 如果你的应用程序正在后台运行并响应用户输入,说明了进程正在创建(ProgressBar和 ProgressDialog在这里很有作用)。
  • 如果是游戏编程,应该在一个子线程里做位移运算。
  • 如果你的应用程序有一个比较耗时的初始化过程,可以考虑显示一个开场动画或者尽可能快的显示主窗口然后异步的填充其他部分。其中任意一种方法,都可以让用户感觉不到应用程序的停止。