简析Handler、Looper跟MessageQueue三者的关系

简析Handler、Looper和MessageQueue三者的关系

Android开发中,Handler用的非常多,因为它和AsyncTask一样是系统提供给我们的异步的通信机制。能够将一些更新和别的不适合放在UI主线程的操作放到它们中去。

Handler的作用主要有两个:一是在线程中发送消息, 二是获取和处理消息。既可以发送消息sendEmptyMessage(int what) ,也可以发送指定的消息sendMessage(Message msg),还可以利用msg.obj的属性去传递我们需要的参数甚至对象,使原本的通信机制更为强大。


Handler发送消息的机制

Handler的出现,解决了在非UI主线程更新UI组件数据的问题。如上面提到的,我们使用handler.sendEmptyMessage(int what)  或者 sendMessage(Message msg)去发送消息,这个消息就会放去消息队列MessageQueue中,MessageQueue是个先进先出的队列,Handler按照这个顺序一直从消息队列MessageQueue中获取消息Message,并且按照约定的方式去处理这些消息。下面是最简单的发送空消息给handler去进行处理:

private Handler handler = new Handler(){
		@Override
		public void handleMessage(Message msg)
		{
			if(msg.what == 0x101)
			{	//约定如何处理不同的msg消息
				Log.i("print handler message", "msg.what = 0x101");
			}
			else if(msg.what == 0x201)
			{
				Log.i("print handler message", "msg.what = 0x201");				
			}
		}
	};
	
	/**
	 * 发送空消息
	 */
	private void sendMessageA()
	{
		handler.sendEmptyMessage(0x101);
	}
	
	private void sendMessageB()
	{
		handler.sendEmptyMessage(0x201);
	}
使用Handler的过程中,想必大家都会发现,如果在UI主线程中直接使用Handler去发送消息是没问题的,但放在非主线程中就会报错了。为什么呢?


Loop和MessageQueue的关系

这是因为非主线程中并不会自动创建Looper对象。Looper是顾名思义,是一个“圈”,负责管理消息队列MessgeQueue。Looper会不断(一直循环到队列中不再有message为止)从MessageQueue中读取消息并交给Handler去处理。因为我们在主线程中handler发送消息,主线程是自动帮我们初始化创建一个Looper对象的,而且每个线程只能有一个Looper。因为当然不允许同时有2个或以上的Looper对消息队列读取消息,这样就会导致类似“锁”的问题。也就是说,非UI主线程中,是不会自动帮我们创建这个Looper的。所以解决方法就是在发送消息前,先创建一个( prepare() ),然后开启它( loop() )。这样它才能正常的从消息队列中读取管理消息。


还是用上面的例子,不过改成在子线程中去创建Handler并且处理。

{
		private Handler mHandler;
		
		@Override
		public void run() {
			// 创建Looper
			Looper.prepare();
			mHandler = new Handler(){
				@Override
				public void handleMessage(Message msg)
				{
					if(msg.what == 0x101)
					{	//约定如何处理不同的msg消息
						Log.i("print handler message", "msg.what = 0x101");
					}
					else if(msg.what == 0x201)
					{
						Log.i("print handler message", "msg.what = 0x201");				
					}
				}
			};
			//启动Looper,这样它才能从消息队列中读取管理消息
			Looper.loop();
		}
	}
	
	private void sendMessgeInThread()
	{
		MessageThread mThread = new MessageThread();
		//创建Handler
		mThread.start();
		mThread.mHandler.sendEmptyMessage(0x101);
	}

总结三者的关系

从上面分个的来说明,我们已经知道Handler,Looper和MessageQueue分别的作用是什么。这里就总结下它们三者的关系:

情况一,在主线程中

创建Handler  ---->  使用handler发送消息  --->  消息被放入消息队列MessageQueue中  ---->  (主线程自动创建的)Looper负责不断地从消息队列中取出消息,交给Handler --->  Handler再次对不同的消息进行处理  --->  消息message被处理完后,随即被扔弃毁掉,然后继续处理第二条到达的消息message,直到Looper已经将所有消息都读取完。


情况二,在非主线程中

在上面的基础上分别调用Looper.prepare() 和 Looper.loop()方法去创建和启动Looer。创建Handler前调用Looper.prepare() ,创建完毕使用Looper.loop()。 剩下的收发消息和处理消息的过程和情况一是一样的。