Painless Threading

来源:互联网 发布:战翼cg 知乎 编辑:程序博客网 时间:2024/06/05 14:55
Painless Threading
This article discusses the threading model used by Android applications and how applications can ensure best UI performance by spawning worker threads to handle long-running operations, rather than handling them in the main thread. The article also explains the API that your application can use to interact with Android UI toolkit components running on the main thread and spawn managed worker threads.
本文讨论Android中的线程模型,以及应用如何通过产生worker threads来处理长时间操作以确保最佳的UI性能,而不是在主线程中处理这些任务。本文还介绍了与Android UI工具包组件中的主线程进行交互以及产生worker threads的APIs。

The UI thread
UI线程

When an application is launched, the system creates a thread called "main" for the application. The main thread, also called the UI thread, is very important because it is in charge of dispatching the events to the appropriate widgets, including drawing events. It is also the thread where your application interacts with running components of the Android UI toolkit.
当应用被启动时,系统创建一个主线程(main thread)。主线程也被称为UI线程(UI thread)管理事件的发布,如drawing events.它也是与Android UI工具包的运行组件交互的线程.

This single-thread model can yield poor performance unless your application is implemented properly. Specifically, if everything is happening in a single thread, performing long operations such as network access or database queries on the UI thread will block the whole user interface. No event can be dispatched, including drawing events, while the long operation is underway. From the user's perspective, the application appears hung. Even worse, if the UI thread is blocked for more than a few seconds (about 5 seconds currently) the user is presented with the infamous "application not responding" (ANR) dialog.


除非你的应用是正确的,否则这种单线程模型有可能产生低效的性能。特别地,若所有事件都发生在在单一线程中,执行长操作,如在UI线程中访问网络或者数据库查询将阻塞整个用户界面。此时任何其它事件,如drawing events都不会被派发。从用户的角度,应用给人感觉被挂起了。更糟糕地是,若UI线程阻塞时间多达几秒,用户会以为"application not responding"(ANR).

To summarize, it's vital to the responsiveness of your application's UI to keep the UI thread unblocked. If you have long operations to perform, you should make sure to do them in extra threads (background or worker threads).
总之,保证主线程非阻塞非常重要。若你执行长时间操作,你需要在其它的线程(后台线程或工作线程)中执行。

Here's an example of a click listener downloading an image over the network and displaying it in an ImageView:
以下给出单击监听下载一张图片并将其显示在ImageView中的例子:

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      Bitmap b = loadImageFromNetwork();
      mImageView.setImageBitmap(b);
    }
  }).start();

}


At first, this code seems to be a good solution to your problem, as it does not block the UI thread. Unfortunately, it violates the single-threaded model for the UI: the Android UI toolkit is not thread-safe and must always be manipulated on the UI thread. In this piece of code above, the ImageView is manipulated on a worker thread, which can cause really weird problems. Tracking down and fixing such bugs can be difficult and time-consuming.
这段代码貌似没问题,因为它不会阻塞UI线程。然而,它违反了UI单线程模型:Android UI工具集并不是线程安全的,它而且必须在UI线程中执行。所以以上代码中,ImageView在一个工作线程中被执行,这可能导致非常奇怪的问题。调试这种bugs又困难又浪费时间。

Android offers several ways to access the UI thread from other threads. You may already be familiar with some of them but here is a comprehensive list:
Android提供多种方式使其它线程访问UI线程。

以下给出一种很熟悉的步骤访问UI线程:

1).Activity.runOnUiThread(Runnable)
2).View.post(Runnable)
3).View.postDelayed(Runnable, long)
4).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();
}

Unfortunately, these classes and methods could also tend to make your code more complicated and more difficult to read. It becomes even worse when your implement complex operations that require frequent UI updates.
不幸地是,这些类与方法只会使你的代码难以维护。特别是在你实现需要频繁的UI更新操作时这种方法使你的实现更加复杂。

To remedy this problem, Android 1.5 and later platforms offer a utility class called AsyncTask, that simplifies the creation of long-running tasks that need to communicate with the user interface.
为了解决这个问题,Android 1.5+提供了一个工具类AsyncTask来简化一个需要与用户界面交互的长时间运行的任务的创建。

An AsyncTask equivalent is also available for applications that will run on Android 1.0 and 1.1. The name of the class is UserTask. It offers the exact same API and all you have to do is copy its source code in your application.
Android 1.0和1.1中提供了一个AsyncTask类的等价类UserTask,它提供了几乎一模一样的API.

The goal of AsyncTask is to take care of thread management for you. Our previous example can easily be rewritten with AsyncTask:
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);
     }
}

As you can see, AsyncTask must be used by subclassing it. It is also very important to remember that an AsyncTask instance has to be created on the UI thread and can be executed only once. You can read the AsyncTask documentation for a full understanding on how to use this class, but here is a quick overview of how it works:
正如你所看到的,AsyncTask需要被继承。注,AsyncTask实例必段在UI线程中创建并且只被执行一次。你可以阅读AsyncTask文档来了解更详细的使用。以下给出AsyncTask的简介:

1).You can specify the type of the parameters, the progress values and the final value of the task
你需要指明task的参数类型,进度值以及最终值
2).The method doInBackground() executes automatically on a worker thread
doInBackground()方法在一个工作线程中自动执行
3).onPreExecute(), onPostExecute() and onProgressUpdate() are all invoked on the UI thread
onPreExecute(), onPostExecute()和onProgressUpdate()都在UI线程中执行
4).The value returned by doInBackground() is sent to onPostExecute()
doInBackground()方法返回的值被发送给onPostExecute()
5).You can call publishProgress() at anytime in doInBackground() to execute onProgressUpdate() on the UI thread
你可以在doInBackground()方法中的任何时候调用publishProgress()来执行UI线程中的进度更新任务onProgressUpdate()
6).You can cancel the task at any time, from any thread
你可以在任何时候从任何线程中取消任务

Regardless of whether or not you use AsyncTask, always remember these two rules about the single thread model:
不论你是否使用AsyncTask,对于单线程模记住以下两条准则很重要:

1).Do not block the UI thread, and —— 不要阻塞UI线程

2).Make sure that you access the Android UI toolkit only on the UI thread. —— 确保只在UI线程中访问Android UI工具集


详情请见:http://developer.android.com/resources/articles/painless-threading.html

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 yy频道提示禁止游客进入怎么办 口红颜色太艳了怎么办 我在菲律宾想走怎么办 当国家流通货币不够用怎么办 苹果5s账号密码忘记怎么办 钢铁雄心3补给不足怎么办 灯外观颜色太难看了怎么办 被移民公司骗了怎么办 文明5大包锁区怎么办 鸭子被黄鼠狼叼走了怎么办 黄鼠狼再店了拉屎怎么办 我只有信用卡但是又想去嫖怎么办 瑞士退税单掉了怎么办 装了新风噪音大怎么办 意大利 护照被偷了怎么办 请问去意大利要怎么办护照 在意大利护照丢了怎么办 考研二战档案打回原籍怎么办 脸上的肉往下掉怎么办 眼镜带了往下掉怎么办 孩子捅别的孩子眼睛了怎么办 眼睛不小心捅伤怎么办 我的爸爸是小偷怎么办 违停罚款忘记交怎么办 顺风车无人接单怎么办 来例假腰特别疼怎么办 把人撞死了全责怎么办 朝鲜与美合作对付中国怎么办 申请美国大学gpa不够怎么办 武装突袭3有地雷怎么办 辐射4狗肉跟丢了怎么办 洛奇英雄传死绑S怎么办 在老挝遇到坏人带枪怎么办 买了sd卡卡槽塞不下怎么办 现役军人家庭被邻居欺服怎么办 地铁买票买多了怎么办 免税店买的东西转机怎么办 绿能电动车坏了怎么办? 永久单车收不到验证码怎么办 24速山地车档乱了怎么办 新电瓶车被偷了怎么办