Looper、handler、message小结
2015-09-10 09:38
387 查看
Looper:
Looper.prepare();方法:为每个线程创建一个唯一的looper,并与当前线程联系起来。Loop.prepare():这个方法只能调用一次,保证每个Thread只保存一个looper。
<span style="font-size:14px;">public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(true)); } </span>
创建一个looper的时候会创建一个MessageQueue(消息队列):
<span style="font-size:14px;">private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); //与当前线程联系起来 } </span>Looper.loop();方法:不断的获取MessageQueue的message,并通过message.taget.dispatchmessage(msg) 将消息发送出去。
<span style="font-size:14px;">public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg); if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycle(); } } </span>
Hander:是如何与message联系起来的?
<span style="font-size:14px;">public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } </span>
<span style="font-size:14px;"> </span>
<span style="font-size:14px;">mLooper = Looper.myLooper(); 通过这个获取了线程保存的looper. mQueue = mLooper.mQueue; 通过这个将线程保存的looper的messagequeue与hanger的mqueue联系起来。 handler发送消息: </span>
<span style="font-size:14px;"> </span>
<span style="font-size:14px;"></span><pre name="code" class="java"> public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
<span style="font-size:14px;"> public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); }</span>
<span style="font-size:14px;"> public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }</span>
<span style="font-size:14px;"> public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }</span>
<span style="font-size:14px;"> private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }</span>
<span style="font-family:Arial, Helvetica, sans-serif;font-size:14px;"><span style="white-space: normal;"> </span></span>
<span style="font-family:Arial, Helvetica, sans-serif;font-size:14px;"><span style="white-space: normal;">通过msg.target = this; 将message的target指向了handler,然后再将message压入messagequeue中,这样在loop方法中的时候获取到message后通过message.taget.dispatchmessage(msg) 就可以将消息发送到handler中处理。 handler是怎么接收到message的: message通过message.taget.dispatchmessage(msg) ,handler的dispatchMessage()方法如下:通过handlerMessage将消息发送处理。 </span></span><pre name="code" class="java">public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
<span style="font-family:Arial, Helvetica, sans-serif;font-size:14px;"><span style="white-space: normal;"> 这里对消息的处理除了handlerMessage(),还有一个mCallback.handleMessage(msg),还有的是msg.callback: </span></span>
<span style="font-family:Arial, Helvetica, sans-serif;font-size:14px;"><span style="white-space: normal;"> </span></span>所以handler处理消息的方法有三种,常用以下两种:
<span style="font-size:14px;"> Handler dHandler=new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message arg0) { return false; } });</span>
<span style="font-size:14px;">mHandler = new Handler() { @Override public void handleMessage(Message msg) { } };</span>
总结:
1:主线程的时候实例化handler时已经在ui主线程添加了looper,所以不用添加looper,而非主线程的时候实例化handler时必须添加looper,否则会报错误;throw new RuntimeException("No Looper; Looper.prepare() wasn't calledon this thread.");
new Thread()
{
private Handler handler;
public void run()
{
Looper.prepare();
handler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
};
};
Looper.loop();
}
2.整个过程:通过Looper.prepare();给当前线程保存一个唯一的Looper对象,该looper对象创建了一个Message队列。然后handler实例化时获取到当前线程的looper对象,并拿到该looper对象的消息队列。handler调用 sendMessage()方法过程中调用到enqueueMessage()方法,并将要发送的message的target指向当前的发送消息的handler,同时将消息压入要发送消息的handler的消息队列(也就是当前线程looper的消息队列,因为它于handler已经挂钩了),最后looper.loop();该方法不断获取到消息队列的Message,并通过message.taget.dispatchmessage(msg)将消息发送出去。handler可以通过handlerMessage()也可以通过Handler.Callback()获取到发送过来的Message,然后处理。
looper作用:创建当前线程的looper对象,该对象包含了一个消息队列,然后不断的获取消息队列的消息发送出去。
handler作用:获取到当前线程的looper的消息队列,发送消息时将消息的target(相当于要发送的地址)指定,并将消息压入消息队列中。
Handler发送消息有主要有两种,post系列、send系列:
post系列:
public final booleanpost(Runnable r):
Causes the Runnable r to be
added to the message queue. The runnable will be run on the thread to which this handler is attached.
postAtTime(Runnable
r, long uptimeMillis)
Causes the Runnable r to be added to the message queue, to be run at a specific time given by uptimeMillis
postDelayed(Runnable r, long delayMillis)
Causes the Runnable r to be added to the message queue, to be run after the specified amount of time elapses
send系列主要是发送message。
post可以设置发送时间,可以延迟发送,除了handler之外,View也有post的方法:
<span style="font-size:14px;">imageView.post(new Runnable() { @Override public void run() { mAnimation.start(); } });</span>
所以对一些view的ui操作可以通过post更新,其原理是:
View.post(Runnable)方法。在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里。
相关文章推荐
- bash编程实现冒泡排序
- Some Popular Tools for Creating Wireframes
- [置顶]安装虚拟机-linux系统步骤
- 分布式系统架构的基本原则和实践
- 为什么web应用在tomcat启动时报java.lang.ClassCastException异常?
- fopen与读写的标识r,r+,rb+,rt+,w+.....
- 在 Linux 中使用日志来排错
- CentOS简介
- 在 Linux 中使用日志来排错
- Centos上SSH连接过慢原因
- Thread多线程stopSleep顺序问题
- 关于tomcat的gzip压缩后的测试
- 个人学习笔记---linux中断控制
- Mac OS X配置Apache服务器
- Linux的chattr与lsattr命令
- 如何在 CentOS 7 上安装开源 ITIL 门户 iTOP
- Linux特殊权限
- OPENSTACK 架构设计指南 from Mirantis
- Linux中查看系统资源占用情况的命令
- shell字符串操作