当应用启动,系统会建立一个主线程(main thread)。html
这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget andandroid.view packages))发生交互。java
因此main thread也叫UI thread也即UI线程。android
系统不会为每一个组件单首创建线程,在同一个进程里的UI组件都会在UI线程里实例化,系统对每个组件的调用都从UI线程分发出去。数据库
结果就是,响应系统回调的方法(好比响应用户动做的onKeyDown()和各类生命周期回调)永远都是在UI线程里运行。安全
当App作一些比较重(intensive)的工做的时候,除非你合理地实现,不然单线程模型的performance会很poor。网络
特别的是,若是全部的工做都在UI线程,作一些比较耗时的工做好比访问网络或者数据库查询,都会阻塞UI线程,致使事件中止分发(包括绘制事件)。对于用户来讲,应用看起来像是卡住了,更坏的状况是,若是UI线程blocked的时间太长(大约超过5秒),用户就会看到ANR(application not responding)的对话框。app
另外,Andoid UI toolkit并非线程安全的,因此你不能从非UI线程来操纵UI组件。你必须把全部的UI操做放在UI线程里,因此Android的单线程模型有两条原则:ide
1.不要阻塞UI线程。oop
2.不要在UI线程以外访问Android UI toolkit(主要是这两个包中的组件:android.widget
andandroid.view)。post
根据单线程模型的两条原则,首先,要保证应用的响应性,不能阻塞UI线程,因此当你的操做不是即时的那种(not instantaneous),你应该把他们放进单另的线程中(叫作background或者叫worker线程)。
好比点击按钮后,下载一个图片而后在ImageView中展现:
public void onClick(View v) { new Thread(new Runnable() { public void run() { Bitmap b = loadImageFromNetwork("http://example.com/image.png"); mImageView.setImageBitmap(b); } }).start(); }
这段代码用新的线程来处理网络操做,可是它违反了第二条原则:
Do not access the Android UI toolkit from outside the UI thread.
从非UI线程访问UI组件会致使未定义和不能预料的行为。
为了解决这个问题,Android提供了一些方法,从其余线程访问UI线程:
好比,上面这段代码能够这么改:
public void onClick(View v) { new Thread(new Runnable() { public void run() { final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(bitmap); } }); } }).start(); }
这么改以后就是线程安全的了。
可是,当操做变得复杂的时候,这种代码会变得很是复杂,为了处理非UI线程和UI线程之间更加复杂的交互,能够考虑在worker线程中使用一个Handler
,来处理UI线程中传来的消息。
也能够继承这个类AsyncTask 。
只有在UI线程中的对象才能操做UI线程中的对象,为了将非UI线程中的数据传送到UI线程,能够使用一个 Handler运行在UI线程中。
Handler是Android framework中管理线程的部分,一个Handler对象负责接收消息而后处理消息。
你能够为一个新的线程建立一个Handler,也能够建立一个Handler而后将它和已有线程链接。
若是你将一个Handler和你的UI线程链接,处理消息的代码就将会在UI线程中执行。
能够在你建立线程池的类的构造方法中实例化Handler的对象,而后用全局变量存储这个对象。
要和UI线程链接,实例化Handler的时候应该使用Handler(Looper)
这个构造方法。
这个构造方法使用了一个 Looper
对象,这是Android系统中线程管理的framework的另外一个部分。
当你用一个特定的 Looper
实例来建立一个 Handler时,这个 Handler就运行在这个 Looper
的线程中。
在Handler中,要覆写handleMessage()
方法。Android系统会在Handler管理的相应线程收到新消息时调用这个方法。
一个特定线程的全部Handler对象都会收到一样的方法。(这是一个“一对多”的关系)。
官方Training: 与UI线程通讯:
http://developer.android.com/training/multiple-threads/communicate-ui.html
Guides: Processes and Threads
http://developer.android.com/guide/components/processes-and-threads.html
类参考:
http://developer.android.com/reference/android/os/Looper.html
http://developer.android.com/reference/android/os/Handler.html
http://developer.android.com/reference/android/os/HandlerThread.html
博客:
Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等:
http://www.cnblogs.com/playing/archive/2011/03/24/1993583.html