Android文章翻译之Painless Threading
轻松使用线程(Painless Threading)
这篇文章介绍了Android的线程模型和AsyncTask等内容,值得一看。以下的翻译的内容:
此文章讨论的是用于Android应用程序的线程模型,和应用程序怎样利用Worker Thread代替主线程执行长时间的操作,用以确保最好的UI表现。该文章同样解释了应用程序在主线程与worker Thread中和Android UI工具包组件交互的相关API。
UI线程(The UI Thread)
当应用程序运行的时候,系统会为应用程序创建一个主线程。它同样被称作UI 线程,它管理着分派事件给合适的部件,包括绘制事件。同样它也是你的应用程序和Android UI 控件交互的线程。
例如:当你触摸屏幕上的按钮,UI线程会分派触摸事件给按钮,设置按下状态和发送一个更新请求到事件队列。UI线程让请求出队列并且通知组件重画自己。
如果你的应用程序设计不合理 单线程模型会造成极低的效率。特别的,如果任何事都在一个线程中执行,在UI线程执行长时间的操作例如网络连接和数据查询会阻塞整个用户界面。这样会造成没有事件会被分发,包括绘制事件。用户会认为程序出现了挂载。甚至更糟,UI线程阻塞超过大概5秒就会出现臭名昭著的”application not responding”(ANR)对话框。
如果你想看看情况有多坏,写一个简单的应用程序,绘制一个button,在点击事件里调用Thread.sleep(2000)。点击按钮,它会在按下状态停留了2秒再回到正常状态。这样会让用户感觉到应用程序反应很慢。
做个总结:保证UI线程不被阻塞与你应用程序流畅性关系重大。你应该确保长时间的操作运行在其他的线程(background or worker threads)。
下面是一个下载图片然后呈现在ImageView的例子:
public void onClick(View v) { new Thread(new Runnable() { public void run() { Bitmap b = loadImageFromNetwork(); mImageView.setImageBitmap(b); } }).start(); }
首先,这段代码看似很好的解决了问题,它没有阻塞UI线程。不幸的是,这违反了UI的单线程模型:Android UI控件是非线程安全的,必须在UI线程中操作。在上面这段代码中,ImageView在worker线程中易做图作会导致很多奇怪的问题。跟踪和改正这样的bug是很困难且比较耗时的。
Android提供了几种方法让其他线程访问UI线程。你可能已经熟悉了一些,下面是完整的列表:
· Activity.runOnUiThread(Runnable)
· View.post(Runnable)
· View.postDelayed(Runnable,long)
· Handler
你可以用其中的一些方法改正之前的那个例子:
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更新时甚至更糟。
为了解决这种问题,Android平台在1.5后提供了一个实用的工具类叫做AsyncTask,简化了长时间需要和用户界面交流的任务。
在Android1.0和1.1中UserTask的作用相当于AsyncTask。
AsyncTask的目标是帮助你更轻松的管理线程。上一个例子可以利用AsyncTask重写:
public void onClick(View v) {
new DownloadImageTask().execute("/2011/1013/20111013014500861.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的用法,下面是一个让你快速使用的概要:
你能够使用泛型指定类型来定制参数,进度值和任务的返回值
doInBackground()方法是在workerthread中自动调用的
onPreExecut(),onPostExecut()和onProgressUpdate()是在UI线程中调用的
doInBackground()的返回值传递给onPostExecute()
你可以在doInBackground()中任何时间调用publishProgress()方法使得在UI线程中执行onProgressUpdate()方法
你能够在任何线程和任何时候取消任务
在官方文档中,你可以阅读几个复杂的例子的源代码,如:Shelves(ShelvesActivity.java 和AddBookActivity.java) 和 Photostream(LoginActivity.java,PhototstreamActivity.java和ViewPhotoActivity.java).强烈建议阅读Shelves的源代码来学习如何配置改变中保持任务和如何在activity销毁时适当的取消它们。
无论你是否使用AsyncTask,记住单线程模型的两个规则:
1:不要阻塞UI线程
2:确保只在UI线程中访问AndroidUI控件
AsyncTask使这两项变的更简单去做。
以上就是全部内容,欢迎大家和我交流。
摘自:ldj299的专栏
补充:移动开发 , Android ,