Looper
类用来为一个线程跑一个消息循环。html
线程在默认状况下是没有消息循环与之关联的,Thread类在run()方法中的内容执行完以后就退出了,即线程作完本身的工做以后就结束了,没有循环的概念。java
调用Looper类的 prepare()
方法能够为当前线程建立一个消息循环,调用loop()
方法使之处理信息,直到循环结束。android
大多数和消息循环的交互是经过 Handler
类进行的。安全
下面是一个典型的实现:多线程
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
Handler类用来发送和处理消息(Message)以及和线程的消息队列(MessageQueue
)关联的Runnable对象。app
每个Handler对象都仅和一个线程及这个线程的消息队列关联。ide
一个特定线程的全部Handler对象都会收到一样的方法。(这是一个“一对多”的关系)。oop
当你建立一个新的Handler对象,它会和建立它的这个线程/线程的消息队列绑定,从那个时刻开始,它将向这个消息队列传递消息和runnable对象,而且当它们从队列中出来时执行它们。post
Handler主要有两种用途:ui
1.合理调度安排消息和runnable对象,使它们在未来的某个点被执行。
2.将一个动做入队安排在非当前线程执行。
调度消息是经过一系列的post方法和sendMessage方法。
post方法容许你向消息队列中入队一些Runnable对象,在它们被接收到的时候会被调用,(实际上post方法也就是将runnable对象包装在消息里,而后再经过sendMessage方法实现),post方法有:
postAtFrontOfQueue(Runnable r)
postAtTime(Runnable r, Object token, long uptimeMillis)
postAtTime(Runnable r, long uptimeMillis)
postDelayed(Runnable r, long delayMillis)
sendMessage方法容许你入队一个消息对象(Message),包含一个bundle数据,以后将会被Handler的handleMessage(Message)方法所处理。
(这个须要你实现一个Handler的子类)。
sendMessage方法有:
sendEmptyMessage(int what)
sendEmptyMessageAtTime(int what, long uptimeMillis)
sendEmptyMessageDelayed(int what, long delayMillis)
sendMessage(Message msg)
sendMessageAtFrontOfQueue(Message msg)
sendMessageAtTime(Message msg, long uptimeMillis)
sendMessageDelayed(Message msg, long delayMillis)
一个线程对应一个Looper,有一个消息队列,可是能够关联多个Handlers。
当你的应用进程被建立的时候,应用进程的主线程(main thread)就创建一个消息队列,操纵top级别的应用对象(好比activities、broadcast receivers等)和它们建立的任何窗口。
由于效率的考虑,全部的View和Widget都不是线程安全的,因此相关操做强制放在同一个线程,这样就能够避免多线程带来的问题。这个线程就是主线程,也即UI线程。
你能够建立本身的线程,经过一个Handler对象和应用的主线程通讯。
若是你将一个Handler和你的UI线程链接,处理消息的代码就将会在UI线程中执行。
新线程和UI线程的通讯是经过从你的新线程调用和主线程相关的Handler对象的post或者sendMessage方法实现的,给定的Runnable或Message将会在Handler的消息队列中,而且在合适的时间被处理。
总的来讲,共有5种方式从非UI线程和UI线程通讯:
还有就是经过Handler,或者使用AsyncTask。
具体参见以前的博文:http://www.cnblogs.com/mengdd/p/3418780.html
消息处理机制中,消息存放在一个消息队列中,而线程围绕这个队列进入一个无限循环,直到程序退出。
若是队列中有消息,线程就会把消息取出来,并分发给相应的Handler进行处理;
若是队列中没有消息,线程就会进入空闲等待状态,等待下一个消息的到来。
Android程序的运行入口点能够认为是android.app.ActivityThread类的main()方法(源码2.3.3):
public static final void main(String[] args) { // other codes... // 建立主线程循环 Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); // other codes... // 进入当前线程(此时是主线程)消息循环 Looper.loop(); // other codes... thread.detach(); // other codes... }
这个main()方法里面为程序建立了主线程循环。
Looper类中的主线程建立方法prepareMainLooper():
/** * Initialize the current thread as a looper, marking it as an application's * main looper. The main looper for your application is created by the * Android environment, so you should never need to call this function * yourself. {@link #prepare()} */ public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); // other codes... }
上面这个方法是专门为建立应用程序的主线程调用的,其余线程都不该该调用这个方法,而应该调用prepare()方法。
主线程的Looper对象建立好以后会存在Looper类的成员变量mMainLooper里,经过一个get方法能够获取到:
/** * Returns the application's main looper, which lives in the main thread of * the application. */ public synchronized static final Looper getMainLooper() { return mMainLooper; }
这样以后,程序中其余线程就能够获取主线程的消息循环对象,从而和主线程通讯。
非主线程建立消息循环时,调用的是Looper类的prepare()方法,其实建立主线程的方法实质也调用了prepare方法:
/** * Initialize the current thread as a looper. This gives you a chance to * create handlers that then reference this looper, before actually starting * the loop. Be sure to call {@link #loop()} after calling this method, and * end it by calling {@link #quit()}. */ public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException( "Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }
这个方法会调用Looper类的私有构造方法,建立Looper类对象。
private Looper() { // 私有构造方法,在prepare()方法里面调用 // 建立消息队列 mQueue = new MessageQueue(); mRun = true; // 当前线程 mThread = Thread.currentThread(); }
不论是不是主线程,prepare以后须要调用Looper类的loop()方法,能够看做是进入消息循环:
/** * Run the message queue in this thread. Be sure to call {@link #quit()} to * end the loop. */ public static final void loop() { // 进入当前线程的消息循环 Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { // 从队列中取出消息 Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } // other codes... // 分发消息 msg.target.dispatchMessage(msg); // 消息的target是Handler类型的对象 // other codes... // 释放清理 msg.recycle(); } } }
前面建立了消息循环,而且进入了这个循环,可是消息队列中的消息是如何加入和处理的呢?是经过Handler。
Handler构造:
Handler有几个构造重载,若是构造时不提供Looper类对象参数,会获取当前线程的Looper对象,即将当前线程的消息循环做为Handler关联的消息循环。
前面说过,不是全部线程都有一个消息循环,因此若是当前线程没有消息循环,而构造Handler对象时又没有指定Looper对象,则会抛出一个运行时异常:
mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); }
若是没有抛出异常,Handler对象构造好以后,它就关联了相应的Looper实例和消息队列实例,即完成绑定。
消息发送:
Handler对象的post方法和sendMessage方法本质上都是发送消息的方法(post类方法实质上是调用了sendMessage方法)。
所谓发送消息就是把消息放入消息队列中的合适位置,而且把消息的target设置为本Handler对象。
(这里将消息加入队列,也有一些什么线程唤醒的事儿我们不深刻讨论了)。
能够添加,也就相应地有一些移除方法。
消息处理:
在上面的Looper.loop()方法中,调用了消息对象target(即发送这个消息的Handler对象)的dispatchMessage()方法。
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { // 首先,处理Message本身的callback,调用其run方法 if (msg.callback != null) { handleCallback(msg); } else { // 其次,调用Handler自留的接口对象 // 这个成员变量声明时的注释以下: /** * Callback interface you can use when instantiating a Handler to * avoid having to implement your own subclass of Handler. */ if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } // 最后,调用handleMessage方法处理消息,Handler类中这个方法为空,子类能够重写这个方法 handleMessage(msg); } }
Handler类的handleMessage()方法默认实现为空:
/** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }
上面的代码中也解释了为何一个消息队列能够关联不少个Handler对象,由于虽然队列只有一个,可是消息的target是当时把它加入的Handler对象。
因此当队列中的消息处理的时候,也会找到当时送它来的Handler对象,调用其相应的dispatchMessage()方法,进而调用其中的handleMessage()方法或者mCallback成员的handleMessage()方法来进行处理。
Handler:http://developer.android.com/reference/android/os/Handler.html
Looper:http://developer.android.com/reference/android/os/Looper.html
比较好的几个博文:
Android应用程序线程消息循环模型分析:http://blog.csdn.net/luoshengyang/article/details/6905587
Android应用程序消息处理机制(Looper、Handler)分析:http://blog.csdn.net/luoshengyang/article/details/6817933
Android的消息队列模型:http://www.cnblogs.com/ghj1976/archive/2011/05/06/2038469.html
Android中的Handler, Looper, MessageQueue和Thread:http://www.cnblogs.com/xirihanlin/archive/2011/04/11/2012746.html
本博客其余相关博文:
Android中的UI线程与非UI线程:http://www.cnblogs.com/mengdd/p/3418780.html
说明:本文相关源码是Android 2.3.3版本的。