现在的位置: 首页 > 综合 > 正文

Android线程间通信——Looper Handler

2017年09月20日 ⁄ 综合 ⁄ 共 3656字 ⁄ 字号 评论关闭

首先先搞清楚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:线程,负责调度整个消息循环,即消息循环的执行场所。

关系

HandlerLooperMessageQueue就是简单的三角关系。LooperMessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定LooperMessageQueue

这样说来,多个Handler都可以共享同一LooperMessageQueue了。当然,这些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();

子线程间的通信实现原理跟上面是一样的

抱歉!评论已关闭.