首先先搞清楚Looper handler messageQuee之间的关系
职责
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
关系
Handler,Looper和MessageQueue就是简单的三角关系。Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。
这样说来,多个Handler都可以共享同一Looper和MessageQueue了。当然,这些Handler也就运行在同一个线程里。
· Handler的处理过程运行在创建Handler的线程里
· 一个Looper对应一个MessageQueue
· 一个线程对应一个Looper
· 一个Looper可以对应多个Handler
我们知道获取到主线程的handler 只要
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
就可以了。子线程只要持有主线程的mHandler就可以给主线程发消息。
那么,主线程如何给子线程发消息,或者说子线程之间怎么进行消息通信?
先看子线程
private static class Worker implements Runnable {
private final Object mLock = new Object();
private Looper mLooper;
/**
* Creates a worker thread with the given name. The thread then runs a
* {@link android.os.Looper}.
*
* @param name
* A name for the new thread
*/
Worker(String name) {
Thread t = new Thread(null, this, name);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
synchronized (mLock) {
while (mLooper == null) {
try {
mLock.wait();
} catch (InterruptedException ex) {
}
}
}
}
public Looper getLooper() {
return mLooper;
}
public void run() {
synchronized (mLock) {
Looper.prepare();
mLooper = Looper.myLooper();//得到该线程的looper
mLock.notifyAll();
}
Looper.loop();//让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作
}
public void quit() {
mLooper.quit();
}
下面创建一个该子线程的handler ,如下:
mAlbumArtWorker = new Worker("album art worker");//创建一个线程
mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());//得到该线程的handler
Handler实现,主要在构造方法中是否包含子线程的looper对象
public AlbumArtHandler(Looper looper) {
super(looper);//创建同拥有looper的子线程中的handler
}
因此,
Handler
处理消息总是在创建
Handler
的线程里运行。而我们的消息处理中,不乏更新
UI
的操作,不正确的线程直接更新
UI
将引发异常。因此,需要时刻关心
Handler
在哪个线程里创建的。
public class AlbumArtHandler extends Handler {
private long mAlbumId = -1;
public AlbumArtHandler(Looper looper) {
super(looper);//创建同拥有looper的子线程中的handler
}
@Override
public void handleMessage(Message msg) {//处理消息是在创建handler的线程里执行
long albumid = ((AlbumSongIdWrapper) msg.obj).albumid;
long songid = ((AlbumSongIdWrapper) msg.obj).songid;
String albumName = ((AlbumSongIdWrapper) msg.obj).albumName;
if (msg.what == GET_ALBUM_ART
&& (mAlbumId != albumid || albumid < 0)) {
// while decoding the new image, show the default album art
Message numsg = mHandler.obtainMessage(ALBUM_ART_DECODED, null);
mHandler.removeMessages(ALBUM_ART_DECODED);
mHandler.sendMessageDelayed(numsg, 300);
Bitmap bm = MusicUtils.getArtwork(MediaPlaybackActivity.this,
songid, albumid, albumName);
if (bm == null) {
bm = MusicUtils.getArtwork(MediaPlaybackActivity.this,
songid, -1, albumName);
albumid = -1;
}
if (bm != null) {
mAlbumBm = null;
mAlbumBm = bm;
// while decoding the new image, show the default album art
numsg = mHandler.obtainMessage(ALBUM_ART_DECODED, bm);
mHandler.removeMessages(ALBUM_ART_DECODED);//mHandler是主线程的handler
mHandler.sendMessage(numsg);<span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">//给主线程发消息</span>
}
mAlbumId = albumid;
}
}
}
主线程获取到子线程的handler
mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());//得到该线程的handler
就可以给子线程发消息了。
mAlbumArtHandler.removeMessages(GET_ALBUM_ART);
Message msg = mAlbumArtHandler.obtainMessage(GET_ALBUM_ART,
new AlbumSongIdWrapper(albumid, songid, albumName));
msg.arg1 = metaChanged ? 1 : 0;
msg.sendToTarget();
子线程间的通信实现原理跟上面是一样的