`
zhy20045923
  • 浏览: 153352 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Thread,Looper,Handler,Message,MessageQueue,MessagePool之间的关系

 
阅读更多

多线程与异步
Main Thread & UI Thread
当程序启动的时候Android会自动创建一个进程和一个线程,这个线程负责界面更新,收集系统事件和用户的操作事件等并分配给对应的组件,所以这个线程非常重要 被称为主线程,因为所的和UI有关的操作都是在这个线程当中进行的所以也被称作UI线程。所以说默认情况下主线程和UI线程指的是同一个线程。For instance, when the user touches a button on the screen, your app's UI thread dispatches the touch event to the widget, which in turn sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues the request and notifies the widget that it should redraw itself.

Android的UI系统参考了很多SWT的设计模式。比如,UI线程机制,底层JNI实现 etc.

Android 的UI系统是非线程安全的,意思是说只有创建UI的线程(也就是主线程)才可以对UI进程操作。如果我们在其它线程中执行了一些操作,而这些操作的结果又需要通过UI展现给用户,必需把这更新UI的操作转移到到UI线程中执行。

很多Java起步的程序员对UI线程中的"消息循环"会感觉陌生。其实就是在线程内部有一个死循环一直监听系统事件(用户的操作等)并把任务分发给对应的组件(有兴趣的可以看看NDK附带的native-activity的一个sample,在c中的实现方式就是一个while(1)的死循环)。主线程通过Looper实现了消息的循环处理。

The ralationship between Handler,Message,MessageQueue and Looper?
如果一个线程里边有一个死循环,那么这个循环就会一直在死循环里边循环,并且这个线程不会过多的cpu资源,那么这个线程肯定的阻塞的。如果线程只是一直循环没有什么意义,实际情况通常需要线程根据不同的条件运行不同的方法。我们通常的作法可能会加一个switch开关,根据条件的不同去调用不同的方法。

线程间通信(最常见的就是,worker线程需要更新UI),这个时候实际是包含两个内容:一,数据的传递;二,方法的传递; Android中的Message用于数据传递,而Handler就是方法传递(其实是方法的执行者,Handler会把这个方法放到Handler所在的线程当中去执行);MessageQueue是Message的容器和Java中的Queue一样都是容器,只不过Message Queue是专门用于装载Message的容器。Looper则是一个线程中的死循环用于管理MessageQueue,它负责阻塞读取MessageQueue中的信息(如果MessageQueue中没有信息会一直在那里),挨个读取并把这个Message分发给对应的Handler去执行。

通过一个小例子+源码追踪下它们之间是怎么工作的,关系是什么样的

public class HandleMessageTrackActivity extends Activity {
		final static int SHOW_ALERT = 1025;
		Activity mActivity;
		TextView displayText;
		Handler mHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				switch (msg.what) {
				case SHOW_ALERT:
					showAlert((String) msg.obj);
					break;
				}
			}
		};

		@Override
		protected void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			mActivity = this;
			displayText = new TextView(this);
			setContentView(displayText);
			displayText.setText("Just ignore me");
			new Thread() {
				@Override
				public void run() {
					String Greetings = "Greetings from another Thread";
					mHandler.obtainMessage(SHOW_ALERT, Greetings)
							.sendToTarget();
				}
			}.start();
		}

		private void showAlert(String content) {
			AlertDialog.Builder builder = new Builder(mActivity);
			builder.setMessage(content);
			builder.create().show();
		}
	}


首先看一下mHandler.obtainMessage(SHOW_ALERT, Greetings).sendToTarget();会执行什么。 通过查看Handler的源码发现执行了下边的代码。

	public final Message obtainMessage(int what, Object obj) {
		return Message.obtain(this, what, obj);
	}



接着查看Message中的代码,
	public static Message obtain(Handler h, int what, Object obj) {
		Message m = obtain();
		m.target = h;
		m.what = what;
		m.obj = obj;
		return m;
	}

	/***
	 * Return a new Message instance from the global pool. Allows us to* avoid
	 * allocating new objects in many cases.
	 */
	public static Message obtain() {
		synchronized (mPoolSync) {
			if (mPool != null) {
				Message m = mPool;
				mPool = m.next;
				m.next = null;
				return m;
			}
		}
		return new Message();
	}


看到这里我们应该明白为什么Google建议我们使用obtainMessage而不是new一个Message.这也是符合了Android中的对象回收机制。

public void sendToTarget() {  
		//targe就是一个Handler
		target.sendMessage(this);
	}
	//sendMessage()会调用下面的sendMessageAtTime()把Message加入MessagQueue;
	public boolean sendMessageAtTime(Message msg, long uptimeMillis){ 
		boolean sent = false; 
		MessageQueue queue = mQueue;  
		if (queue != null) {     
			msg.target = this;     
			sent = queue.enqueueMessage(msg, uptimeMillis);    
			}else {   
				RuntimeException e = new RuntimeException(    
						this + " sendMessageAtTime() called with no mQueue");    
				Log.w("Looper", e.getMessage(), e);   
				} 
		return sent;
		}
	}

到此我们的Message对象被加入到了Handler所在线程(也就是主线程)中的MessageQueue这个存储和管理Message的容器当中。下一步就该由Looper接手一个一个的取出Message对象处理了。Looper最主要的方法就是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;      
					}    
				if (me.mLogging!= null)
					me.mLogging.println(">>>>> Dispatching to " + msg.target + " "    + msg.callback + ": " + msg.what );      
				msg.target.dispatchMessage(msg);//target of a msg is a Handler  
				if (me.mLogging!= null) me.mLogging.println(       
						" Finished to    " + msg.target + " "     
				+ msg.callback);//msg.callback is a Runnable      
				msg.recycle();    
				}  
			}
		}
				}
			}
		}
	}


Looper会一直阻塞读取MessagQueue中的Message对象(Message msg = queue.next()),当读取到一个Message时就会调用msg.target.dispatchMessage(msg)把这个Message分发给对应的Handler去处理,等Handler把任务处理完了再接着读取下一个Message对象并处理。

	/*** Handle system messages here.*/
	public void dispatchMessage(Message msg) { 
		if (msg.callback != null) {      
			handleCallback(msg);
			// call the run method of the runnable object I guess   
			} else {     
				if (mCallback != null) {  
					if (mCallback.handleMessage(msg)) 
					{         
						return; 
						}      
					}      
				handleMessage(msg);
				}
		}
		}
	}


最后回来了我们的handlerMessage(msg);这个方法中。如果是用的不是sendMessage是是Hadler.post(Runnable)会调用

private final void handleCallback(Message message) {    message.callback.run();}
这就是为什么在Handler中post的Runnable不会开启一个新的线程的原因。经过上面的追踪我们应该能明白不是所有 的线程都可以有Handler去执行handlerMessage或者处理Runnalbe的。其必要条件就是这个线程要有一个一直循环的Looper.Looper一直循环肯定要有一个方法可以退出循环。
public void quit() {    Message msg = Message.obtain();    // NOTE: By enqueueing directly into the message queue, the    // message is left with a null target.  This is how we know it is    // a quit message.    mQueue.enqueueMessage(msg, 0);}


当我们调用msg.sendToTarget()的时候,我们的msg对象应付被压入MessageQueue的尾部。Looper在MessageQueue的另一端一个一个的读取信息并处理。根据msg的target属性把cpu分配给对应的Handler去执行任务,这时Handler会根据msg中的属性调用msg.handleMsg()或者msg.callback.run();当一个msg中的消息处理完返回之后Looper会把这个msg放入msgPool当中方便下次再重复利用。从而减少对象的创建。Looper再从MessageQueue中读取下一个信息,如此反复。。

理解了这些其实就不难想象ANR是如何实现的了。当用户执行操作(比如点击了一个按钮)系统会生成一个Message对象,把用户操作的信息写入Message对象,并把这个Message对象压入MessageQueue队列的尾部。系统过一段时间(一般是五秒)后会再来检查,刚刚放入的信息是不是已经被处理了,如果信息还在队列中就表明。处理前面信息的过程当中发生的阻塞,用户的操作没有及时得到响应。系统弹出ANR对话框。

作个总结:

  因为UI线程需要保持一直运行的状态,所以要有一个循环保持这个线程不会死掉,但这个线程又必需阻塞,以减少cpu的消耗。android中的这个循环就是通过Looper实现的。有了这个 Looper,Looper就占据了整个线程,导致所有的方法想在些线程中运行就必需通过这个Looper,所以要有个方法可以进入这个Looper的内部。MessageQueue就担当了这个通道 的角色。Message担当了集合的角色。所有在UI线程中运行的方法都必需通过MessageQueue进入Looper内部,不管 是用户定义的方法还是系统事件包括onCreate(),onStop(),用户点击事件etc..

MessageQueue包含两个方法,next()和enquenceMessage(),一个用于读取message,一个用于写入message,它们的访问都是通过jni访问的C层,message也是存储在C层的。在next方法中,如果messagequeue中没有消息,则进入wait。在写入消息时,再进行唤醒操作
  • 大小: 22.3 KB
分享到:
评论
1 楼 ChenJavaNet 2012-03-04  
很有研究精神 跟你学习了

相关推荐

    活用Android的Message Queue

     你可以诞生Handler之对象来与Looper沟通,以便push新讯息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的讯息。  线程A的Handler对象参考可以传递给别的线程,让别的线程B或C等能送讯息来给...

    活用Android的Message_Queue(2)

     UI thread 通常就是main thread,而Android启动程序时(即诞生Process时)会替它建立一个Message Queue。  当然需要一个Looper之对象,来管理该Message Queue。  我们可以诞生Handler之对象来push新讯息到...

    Thread、Handler和HandlerThread关系详解

    ,这个题目有点意思,对于很多人来说,可能对Thread和Handler很熟悉,主要涉及到Android的消息机制(Handler、Message、Looper、MessageQueue),详见《 从Handler.post(Runnable r)再一次梳理Android的消息机制(以及...

    了解Android核心:Looper,Handler和HandlerThread

    Handler 在 MessageQueue 中以任务形式排队,Looper 在任务出现时执行它们 MessageQueue. Looper 使线程保持活动状态,循环 MessageQueue 并向相应 Handler 的进程发送消息。 Thread 通过调用 Looper 的 quit() ...

    android+多线程机制的讲解和例子

    1.Looper:一个线程可以产生一个Looper对象,由它来管理此线程里的Message ...每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。

    Android 面试宝典

    Andriod提供了Handler和Looper来满足线程间的通信.Handler先进先出原则.Looper类用来管理特定线程内对象之间的消息交换(Message Exchange). 1)Looper:一个线程可以产生一个Looper对象,由它来管理此线程里的Message ...

    Mindroid.cpp:Mindroid.cpp是一个受Google Android操作系统启发的应用程序框架

    Mindroid.cpp C ++应用程序框架Mindroid是一个应用程序框架... 消息传递和并发框架主要基于Thread,Looper,Message,MessageQueue和Handler类。 为了方便起见,还有AsyncTask类,对于进程间通信,还有其他一些类,例

    ANRCatcher:一种判断是否发生ANR的方法

    在进行分析之前如何进行ANR的捕获前,这里需要对MainThread、Looper、Handler、MessageQueue、ActivityThread这几个类之间的关系做一个介绍,这个将是我们进行ANR捕获的一个关键点。 一切的开始--创建ActivityThread...

    Android App在线程中创建handler的方法讲解

    5.Looper:消息循环,从MessageQueue中取出Message进行处理; 6.HandlerThread:继承Thread,实例化时自动创建Looper对象,实现一个消息循环线程. 在Android开发中经常会使用到线程,一想到线程,一般都会想到: new ...

    Android中的消息处理实例之二

    本文介绍了Android中的消息处理机制,给出了Android消息处理中的几个重点类Handler、Message、MessageQueue、Looper、Runnable、Thread的详细介绍,提供了两个消息处理的实例代码,并深入Android源代码分析了使用...

    全面总结Android中线程的异步处理方式

    一、概述 Handler 、 Looper 、Message 这三者都与...其实Looper负责的就是创建一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的创建者就是一个或多个Handler 。 二、源码解析

    Android中的消息处理实例之一

    本文介绍了Android中的消息处理机制,给出了Android消息处理中的几个重点类Handler、Message、MessageQueue、Looper、Runnable、Thread的详细介绍,提供了两个消息处理的实例代码,并深入Android源代码分析了使用...

    Android编程之消息机制实例分析

    2.Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的消息。 3. Message Queue(消息队列):用来存放线程放入的消息。 4.线程:UI ...

    浅谈Android中线程池的管理

    说到线程就要说说线程机制 Handler,Looper,MessageQueue 可以说是三座大山了 Handler Handler 其实就是一个处理者,或者说一个发送者,它会把消息发送给消息队列,也就是Looper,然后在一个无限循环队列中进行取出...

    代码分析Android消息机制

    Handler的运行主要由两个类来支撑:Looper与MessageQueue。熟悉开发的朋友都知道在子线程中默认是无法创建Handler的,这是因为子线程中不存在消息队列。当需要创建一个与子线程绑定的Handler时,标准代码如下: ...

    android-thread-producer-consumer-example:线程之间的ProducerConsumer模型示例

    因此,没有使用Looper和MessageQueue 。 我们要读取传感器数据的每个线程上都需要一个新的Handler 。 HandlerThread必须将消息发布到这些线程中的每个线程。 现在,我们仅从UI线程读取数据。 想象一下,我们在UI...

    积分管理系统java源码-alibaba-Interview-preparation:阿里巴巴实习生面试个人准备

    积分管理系统java源码 ...Android线程 为什么要同步 Android中使用多线程的方法 裸new一个Thread(失控线程,不推荐) ...Android线程模型就是消息循环,Looper关联MessageQueue,不断尝试从MessageQueue取出Message来

    Android_Studio_Handler:Android Handler 执行绪教学

    Android Handler 执行绪...每一个执行绪都可以有一个讯息伫列(Message Queue)和一个循环器(Looper),在Android中建立的UI执行绪具有讯息伫列和一个循环器,其它worker执行绪预设并没有(可使用HandlerThread产生具有讯息

    深入Android HandlerThread 使用及其源码完全解析

    关联篇:深入Android的消息机制源码详解-Handler,MessageQueue与Looper关系 关联篇:Handler内存泄漏及其解决方案 本篇我们将来给大家介绍HandlerThread这个类,以前我们在使用线程执行一个耗时任务时总会new一个...

Global site tag (gtag.js) - Google Analytics