如果你想知道这有多糟糕,写一个简单的含有一个按钮的程序,并为按钮注册一个单击事件,并在事件处理器中调用这样的代码Thread.sleep(2000)。在按下这个按钮这后恢复按钮的正常状态之前,它会保持按下状态大概2秒钟。如果这样的情况在你编写的应用程序中发生,用户的第一反应就是你的程序运行很慢。 现在你知道你应该避免在UI线程中执行耗时的操作,你很有可能会在后台线程或工作者线程中执行这些耗时的任务,这样做是否正确呢?让我们来看一个例子,在这个例子中按钮的单击事件从网络上下载一副图片并使用ImageView来展现这幅图片。代码如下: public voidonClick( View v ) { new Thread( new Runnable() { public void run() { Bitmap b = loadImageFromNetwork(); mImageView.setImageBitmap( b ); } }).start(); } 这段代码好像很好地解决了你遇到的问题,因为它不会阻塞UI线程。很不幸,它违背了单线程模型:AndroidUI操作并不是线程安全的并且这些操作必须在UI线程中执行。在这段代码片段中,在一个工作者线程中使用ImageView的方法,这回引起一些很古怪的问题。查处这个问题并修复这个bug会很困难而且也很耗时.
Andriod提供了几种在其他线程中访问UI线程的方法。或许你已经对其中的一些方式很熟悉,但下面是一个更全面的列表: 1)Activity.runOnUiThread( Runnable ) 2)View.post( Runnable ) 3)View.postDelayed( Runnable, long ) 4)Hanlder 上面的任何一个类或方法都可以修复我们前面代码中出现的问题。 public void onClick( View v ) { new Thread( new Runnable() { public void run() { final Bitmap b = loadImageFromNetwork(); mImageView.post( new Runnable() { mImageView.setImageBitmap( b ); }); } }).start(); } 很不幸的是这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。为了解决这个问题,Android1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。 在Android1.0和1.1中具有与AsyncTask相同功能的类UserTask。它提供了完全一样的API,你需要做的只是把它的代码拷贝的你的程序中。 AsyncTask的目标是替你管理你的线程。前面的代码可以很容易地使用AsyncTask重写。
public void onClick( View v ) { new DownloadImageTask().execute( "path"); } private class DownloadImageTask extends AsyncTask { protected Bitmap doInBackground( String urls ) { return loadImageFormNetwork( urls[0] ); } protected void onPostExecute( Bitmap result ) { mImageView.setImageBitmap( result ); } }