Handler、Looper和MessageQueue
2016-02-20 23:26
387 查看
Handler和创建它的线程绑定在一起,每个线程最多只有一个Looper对象,每个Looper只有一个MessageQueue。
当你创建一个Handler实例时,该实例就和创建它的线程、消息队列绑定。
Handler传递Messages给MessageQueue,并且在Looper从消息队列中取出时处理(通过handleMessage(Message msg)方法)。
Handler发送信息通过以下方法完成:
1.post,
2.postAtTime(Runnable, long),
3.postDelayed,
4.sendEmptyMessage,
5.sendMessage,
6.sendMessageAtTime,
7.sendMessageDelayed。
sendMessage(Message msg)方法和post(Runnable r)通过查看源码发现,最后调用的都是同一个方法。
最后到调用了sendMessageDelayed()方法。
看一下getPostMessage(Runnable r),将runnable封装到Message中,返回的是Message。
post(Runnable r),runnalbe是运行在和Handler绑定的线程中,并不是新开了线程运行的。如果创建Handler的线程是主线程就运行在主线程当中。
Handler在实际应用中大多都是应用于更新UI,因为必须在主线程更新UI,不能在子线程中更新。
在子线程当中更新时会报CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
看一下sendMessageDelayed方法:
又调用了sendMessageAtTime方法。
在这里看到了MessageQueue 。
MessageQueue queue = mQueue;
这里返回到Handler的构造方法:(当你使用无参的构造方式时最终会调用该构造方法)
从这里可以看到MessageQueue 是Looper当中的MessageQueue 。
在sendMessageAtTime当中我们可以看到它调用了enqueueMessage()。
在该方法中,msg.target = this;(可以看出msg.target是Handler),然后调用了(MessageQueue 的queue.enqueueMessage方法
加入消息队列。此处就不展开了。
Looper:用于线程轮询信息。默认线程是没有Looper的。可以调用prepare()方法来为线程创建Looper.创建有Looper线程的例子:
在主线程中创建Handler时不用调用Looper.prepare()方法是因为在程序启动的时候,系统已经帮我们自动调用了Looper.prepare()方法。
loop()方法,就是一直循环查询MessageQueue。
查看loop()方法的关键代码:
final Looper me = myLooper();//获取Looper
final MessageQueue queue = me.mQueue;//获取MessageQueue
for (;;) {//循环
Message msg = queue.next()//从MessageQueue当中取出Message
msg.target.dispatchMessage(msg);
// msg.target就是Handler,调用Handler的dispatchMessage方法。
msg.recycle();
}
查看Handler的dispatchMessage()方法。
msg.callback是什么?当你是使用Handler的post(Runnable r)系列的方法时,msg.callback=runnable。所以Handler发送信息使用的是
post()方法时调用handleCallback(msg),使用send()方法则调用的是handleMessage()。
查看handleCallback(msg)方法:
我们发现的是调用了Runnable的run()方法。而不是新启线程调用start()。所以Handler的post(Runnable runnable)参数runnable是运行在Handler绑定的线程,而不是新启线程运行。
当你创建一个Handler实例时,该实例就和创建它的线程、消息队列绑定。
Handler传递Messages给MessageQueue,并且在Looper从消息队列中取出时处理(通过handleMessage(Message msg)方法)。
Handler发送信息通过以下方法完成:
1.post,
2.postAtTime(Runnable, long),
3.postDelayed,
4.sendEmptyMessage,
5.sendMessage,
6.sendMessageAtTime,
7.sendMessageDelayed。
sendMessage(Message msg)方法和post(Runnable r)通过查看源码发现,最后调用的都是同一个方法。
[code]public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
最后到调用了sendMessageDelayed()方法。
看一下getPostMessage(Runnable r),将runnable封装到Message中,返回的是Message。
[code] private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
post(Runnable r),runnalbe是运行在和Handler绑定的线程中,并不是新开了线程运行的。如果创建Handler的线程是主线程就运行在主线程当中。
Handler在实际应用中大多都是应用于更新UI,因为必须在主线程更新UI,不能在子线程中更新。
在子线程当中更新时会报CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
看一下sendMessageDelayed方法:
[code] public final boolean sendMessageDelayed(Message msg, long delayMillis){ if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
又调用了sendMessageAtTime方法。
[code] 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); }
在这里看到了MessageQueue 。
MessageQueue queue = mQueue;
这里返回到Handler的构造方法:(当你使用无参的构造方式时最终会调用该构造方法)
[code] 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; }
从这里可以看到MessageQueue 是Looper当中的MessageQueue 。
在sendMessageAtTime当中我们可以看到它调用了enqueueMessage()。
[code] private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
在该方法中,msg.target = this;(可以看出msg.target是Handler),然后调用了(MessageQueue 的queue.enqueueMessage方法
加入消息队列。此处就不展开了。
Looper:用于线程轮询信息。默认线程是没有Looper的。可以调用prepare()方法来为线程创建Looper.创建有Looper线程的例子:
[code] class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
在主线程中创建Handler时不用调用Looper.prepare()方法是因为在程序启动的时候,系统已经帮我们自动调用了Looper.prepare()方法。
loop()方法,就是一直循环查询MessageQueue。
[code] 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(); } }
查看loop()方法的关键代码:
final Looper me = myLooper();//获取Looper
final MessageQueue queue = me.mQueue;//获取MessageQueue
for (;;) {//循环
Message msg = queue.next()//从MessageQueue当中取出Message
msg.target.dispatchMessage(msg);
// msg.target就是Handler,调用Handler的dispatchMessage方法。
msg.recycle();
}
查看Handler的dispatchMessage()方法。
[code] public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
msg.callback是什么?当你是使用Handler的post(Runnable r)系列的方法时,msg.callback=runnable。所以Handler发送信息使用的是
post()方法时调用handleCallback(msg),使用send()方法则调用的是handleMessage()。
查看handleCallback(msg)方法:
[code] private static void handleCallback(Message message) { message.callback.run(); }
我们发现的是调用了Runnable的run()方法。而不是新启线程调用start()。所以Handler的post(Runnable runnable)参数runnable是运行在Handler绑定的线程,而不是新启线程运行。
相关文章推荐
- 为什么在jsp中写${pageContext.request.contextPath }失效了
- [置顶] NGUI另一种按钮事件触发的方法
- 1007. Maximum Subsequence Sum (25)
- Android Wear 进阶 - 3.1 Creating Custom UIs for Wear Devices-Defining Layouts 创建自定义的手表设备UIs-定义布局
- 【Codeforces#38G】Queue【Splay】【二分】
- [iOS]UIView中的坐标转换
- fixed fluid layout
- iOS-获取UIView的全部层级结构
- UI整理-----part4--UIScrollView
- EasyUI系列学习(十)-Tabs(选项卡)
- 设置UITbaBar和UIBarButtonItem的图片有蓝色图层覆盖
- 百度ueditor学习使用
- LeetCode-334. Increasing Triplet Subsequence
- UINavi中push控制器的时候隐藏TabBar
- leetcode(304) Range Sum Query 2D - Immutable
- 使用 Bluemix™ Live Sync 快速更新 Bluemix 上运行的应用程序实例
- Arduino代码机制-IO
- android小问题--------------------SQLiteDatabase.insert(table, nullColumnHack, values)参数
- scrapy 爬网站 显示 Filtered offsite request to 错误.
- 交换Button中图片与文字的左右位置