本文讨论Android应用程序的线程模型以及应用程序应该如何建立工做线程而不是使用主线程来处理长期运行的操做, 以获得好的UI性能. 本文还解释了你能够用来和Android UI组件交互以及建立线程的 API. html
当一个应用程序启动时, 系统建立一个叫作"main"的线程. 这个主线程也叫UI线程, 它很是重要, 由于它负责将事件分发给合适的widget来处理, 包括绘图事件等. 它也是你的应用程序和运行中的Android UI组件进行交互的线程. 例如, 若是你按下屏幕上的按钮, UI线程会将这个触摸事件分配给该widget, 而该widget将设置它的按下状态并向事件队列一个重绘请求. UI线程从队列中取出请求并通知widget来重画自身. android
单线程模型可能会致使性能不好, 除非你的程序被正确的实现. 特别的, 若是每件事都在同一个线程中进行, 那么耗时长的操做(例如网络访问和数据库查询)将阻塞UI线程, 从而使整个UI没法交互. 在耗时操做进行时, 包括绘画事件在内的全部事件都没法进行分配. 在用户看来, 该应用程序中止了响应. 更糟糕的是, 若是UI线程被阻塞超过一段时间(当前的限制是5秒钟), 那么用户将看到"应用程序无响应"的对话框. 数据库
若是你但愿看看这是多么的糟糕, 那么你能够写一个程序, 建立一个按钮, 它的OnClickListener中调用Thread.sleep(2000). 那么该按钮在按下去之后要等2秒才会谈起, 这时候用户是很是容易感受到程序很慢. 安全
总之, 应用程序UI的响应速度是很重要的, 因此应该避免阻塞UI线程. 若是你须要进行耗时操做, 那么你应该在其余的线程中进行(后台或者工做线程). 网络
下面的例子演示了如何实现一个单击监听器来下载一个图片并将它显示在 ImageView中: less
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
}).start();
} 工具
一开始, 这段代码看起来是个不错的解决方案, 由于它不会阻塞线程. 不幸的是, 它破坏了UI的单线程模型: Android UI工具不是线程安全的, 必须在UI线程中操做. 在上面的代码段中, ImageView在一个工做线程中操做, 这回致使很奇怪的问题. 追踪和解决这样的bug是很是困难的. post
Android提供了一些从其它线程中访问UI线程的方法. 你可能已经对它们之中的某些比较熟悉了: 性能
你能够使用上面的任意一种类和方法来改正以前的错误: url
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
}
}).start();
}
不幸的是, 这些类和方法也会使你的代码更加复杂. 若是你须要实现频繁的UI更新的话就更糟糕了.
为解决这个问题, Android1.5以上的平台提供了一个叫作AsyncTask的工具类.
Android1.0和1.1上也有和它等效的类叫作UserTask, 它提供了彻底同样的接口.
AsyncTask的做用是帮你来管理线程. 咱们将以前的例子用AsyncTask来重写:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<string, void,="" bitmap=""> {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
AsyncTask必须使用建立子类的方式来使用. AsyncTask实例只能在UI线程中建立,而且只能运行一次. AsyncTask documentation 中有它的详细介绍, 这里简单介绍一下:
不管你是否使用 AsyncTask, 记住如下关于单线程模型的两条规则:
AsyncTask 只是让上面两件事情变得更加方便.