线程-Android

Android中轻松使用线程

翻译自 http://android-developers.blogspot.jp/2009/05/painless-threading.html

  当你第一次启动一个Android程序的时候,一个被称为"mian"的线程就被自动创建了。它被称为主线程或者UI线程,它是非常重要的因为负责分发事件给对应的widget(组件),还包含画图的事件。主线程贯穿用户和Android widget的交互的整个过程。例如,你触摸了屏幕上的按钮(Button),UI线程派发(dispatch)触摸(touch)事件给widget,widget设置为按下状态并向事件队列发送一个无效的请求。UI线程把这个请求弹出栈并且通知widget去重画它自己。

单线程模型导致Android程序低效。因为每次单线程去执行长时间的操作如网络请求,数据库查询和drawing event(绘图事件),在这个过程中会阻塞程序的界面(UI)。当长时间的任务正在执行的时候,没有事件(Event)会被派发(dispatch),包括drawing event(绘图事件)。从用户的角度来看,该程序出现了终止。甚至更糟糕的是,如果UI程序被阻塞几秒后(大约5s)就会出现臭名昭著的ANR 对话框。

如果想看一下有多糟糕,你可以写一个简单的带有按钮的程序,按钮的点击事件执行Thread.sleep(2000)代码。该按钮将会保持2秒的按下状态然后恢复正常的状态。这样很容易让用户感到程序很慢。

现在你知道了一定避免在主线程中执行长时间的操作,你可能会使用额外的线程(后台线程或者工作线程)去执行长时间操作。让我们来看看点击从网络下载图片到ImageView里的例子:

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

  首先,代码看上去很好的解决我们的问题,因为它不会阻塞UI线程,不幸的是,它违背了单一线程模型:Android UI工具箱(toolkit)不是一个线程安全的,并且它总是被放在主线程上操作。

这个ImageView被一个工作线程操作,这导致非常不可思议的问题。跟踪和修复这样一个bug很难并且也耗时。

Android提供了几种从其他线程访问主线程的方式。你可能已经使用他们,但是这里是齐全的列表:

以上任何一个类都能修正我们的代码:

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();
}

  不幸的是,这些类和方法导致我们的代码变得复杂和可读性差。当你实现复杂的操作来频繁的更新界面,使用这种方式变得更加糟糕。为了解决这个问题,Android1.5提供了一个公共类叫做AsyncTask,它简化了任务线程和主线程之间的通信。

在Android1.0和1.1也可使用AsyncTask只不过它的名字为UserTask。

AsyncTask的目的就是帮助你管理线程。我们之前的例子很容易被改写如下形式:

public void onClick(View v) {
  new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask {
     protected Bitmap doInBackground(String... urls) {
         return loadImageFromNetwork(urls[0]);
     }

     protected void onPostExecute(Bitmap result) {
         mImageView.setImageBitmap(result);
     }
 }

AsyncTask通过它的子类才能使用。要记住,一个AsyncTask实例必须在主线程创建并且只能被执行一次。完全理解和使用这个类,你可以阅读AsyncTask文档。这里快速的说一下AsyncTask是怎么工作的:

1>可以通过泛型指定它的类型:参数,进度值,任务的结果值。

2>doInBackGround()方法自动在工作线程中只想能够。

3>onPreExecute(),onPostExecute(),onProgressUpdate()方法都在UI线程中执行。

4>doInBackground()方法返回的值被当作参数传递给onPostExecute()方法。

5>你能够在doInBackground()方法里任何时候调用publishProgress()方法在UI线程中去执行onProgressUpdate()方法。

除了官方文档,你可以阅读几个复杂的例子源代码如Shelves(ShelvesActivity.java和AddBookActivity.java)和Photostream(LoginActivity.java,PhotostreamActivity.java和ViewPhotoActivity.java)。我强烈建议阅读Shelves的源代码,看它在配置改变(configuration changes)的时候是如何保存任务的(persist task),当Activity销毁的时候是怎样取消任务的。

不要管它是否使用AsyncTask,总之要记住单线程模型的两个原则(rule):不要阻塞(block)UI线程;确保Android UI toolkit 只能在UI线程中被访问(access)。

AsyncTask使得做这些事情变得更简单。

如果你想学习更酷的技术,加入Google I/O(http://www.google.com/intl/zh-CN/events/io/2011/)。Android团队的成员将在这里进行一些列深层次技术的会议(http://www.google.com/intl/zh-CN/events/io/2010/sessions.html),并且回答你所有的问题。

时间: 2024-08-27 05:31:34

线程-Android的相关文章

为什么用服务不用线程-Android

1.什么是Service? A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.(服务是一个应用程序组件,要么满足在一个应用程

[Android学习系列18]线程,进程,异步的一些事

解决NetworkOnMainThreadException http://www.aitinan.com/4387.html 参考: android进程与线程详解一:进程 android进程与线程详解二:线程 android进程与线程详解三:AsyncTask android进程与线程详解四:线程安全和进程间通信 [Android学习系列18]线程,进程,异步的一些事,码迷,mamicode.com

Android性能优化之使用线程池

在写程序时有些异步程序只执行一遍就不需要了,为了方便经常会写下面的代码 new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); 这样new出来的匿名对象会存在一些问题 1.由于是匿名的,无法对它进行管理 2.如果需要多次执行这个操作就new多次,可能创建多个,占用系统资源 3.无法执行更多的操作 使用线程池的好处 1.可以重复利用存在的线程

Android中的线程

本文转自:http://www.jianshu.com/p/d59b3cce2b54 如何理解线程 在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不可能无限制的产生,并且线程的创建和销毁都会有相应的开销,当系统中存在大量的线程时,系统会通过时间片轮转的方式调度每个线程,在这么多线程中有一个被称为主线程,主线程是指进程所拥有的线程,在JAVA中默认情况下一个进程只有一个线程,这个线程就是主线程.主线程主要处理界面交互相关的逻辑,因为用户随时会和界面发生交互,因此

AsyncTask,IntentService工作原理分析&Android线程池

一,android中的主线程和子线程 android中的主线程可以认为是UI线程,在主线程不可以执行耗时的操作,否则就会给人一种卡顿的感觉.而主线程主要用于处理四大组件,以及处理它们和用户的交互.anroid的子线程的主要功能就是处理耗时操作. 要知道"在android3.0之后,要求网络访问必须在子线程执行,否则会抛出NetWorkOnMainThreadException异常." 二,Android中的线程形态 Android中的线程状态,除了传统的Thread,还包含AsyncT

The Toast in android

Toast can show the help/prompts to user. There have five effect of toast as bellow: 1.default effect: code: Toast.makeText(getApplicationContext(), "默认Toast样式", Toast.LENGTH_SHORT).show(); 2.custom position effect: code: toast = Toast.makeText(g

android Toast大全(五种情形)建立属于你自己的Toast

Toast用于向用户显示一些帮助/提示.下面我做了5中效果,来说明Toast的强大,定义一个属于你自己的Toast. 1.默认效果 代码 Toast.makeText(getApplicationContext(), "默认Toast样式",     Toast.LENGTH_SHORT).show(); 2.自定义显示位置效果 代码 toast = Toast.makeText(getApplicationContext(),     "自定义位置Toast",

Android官方开发文档Training系列课程中文版:Android的JNI相关

原文地址:http://android.xsoftlab.net/training/articles/perf-jni.html JNI的全称为Java Native Interface,中文意思是Java本地接口.它定义了Java代码与C/C++代码之间的交互方式.它是两者的桥梁,支持从动态共享库中加载代码.虽然有些复杂,但是它的执行效率还是蛮高的. 如果你对JNI还不太熟悉,那么可以通过Java Native Interface Specification来了解一下JNI的大致工作流程以及J

[转发]Android 系统稳定性 - ANR(三)

文章都为原创,转载请注明出处,未经允许而盗用者追究法律责任. 很久之前写的了,留着有点浪费,共享之. 编写者:李文栋 http://rayleeya.iteye.com/blog/1956056 1.4 如何避免ANR 1.4.1 ANR发生在主线程,不要阻塞主线程         Android应用程序的所有标准组件全部运行在一个单一的主线程中,在主线程中所做的任何耗时的操作都有可能造成ANR,因为这些耗时的操作会使得主线程没有机会处理用户输入事件或者广播事件.         因此在主线程中