前几天和一位同事讨论Android中Handler和Thread,其中一个问题是:创建Handler时会不会创建Thread?
我对JAVA编程不熟,但直觉告诉我不会:我认为Handler只是用来辅助实现异步操作的东西。当时我拿了GTK+中的idle来做对比,sendMessage就相当于加一个idle函数,系统处理完前面的Message后就会处理这个Message。毕竟没有看过里面的实现代码,所以当时并不确信。今天看了下:
MessageQueue
消息队列MessageQueue是一个以执行时间为序的优先级队列:
o 普通消息的执行为当前时间,先发送的前面,后发送在后面,这是典型的FIFO。
o 最高优先级的消息执行时间为0,所以直接插在队列的最前面,通常会立即执行。
o 而在将来执行的Message相当于timer,执行时间为当前时间+delay的时间。
MessageQueue的函数boolean enqueueMessage(Message msg, long when)用来向队列中插入消息。
Message和GTK+ idle不同之处在于,Message只是一段数据,里面说明了要做什么,但不并知道如何做。而idle带有自己的数据和处理函数,它知道如何做。Message放入队列中后,在处理这些消息时到底要做些什么呢?这就引入了Handler:
Handler
Handler对消息队列的enqueueMessage做了包装,这其实并不重要,因为完全可以直接调用enqueueMessage来实现。重要的Handler把在包装enqueueMessage的同时,把Message的target设成了自己,即为Message指定执行的行为:
if (queue != null) {
? ???msg.target = this;
? ?sent = queue.enqueueMessage(msg, uptimeMillis);
}
这样一来,当前Message被处理的时候就会调用Handler的dispatchMessage,而这个函数就会调用你要实现的虚函数handleMessage了。经过消息队列转了一圈,还是调用了你自己的实现函数,但是同步操作变成了异步操作。
public void dispatchMessage(Message msg) {
? ?? ???if (msg.callback != null) {
? ?? ?? ?? ?handleCallback(msg);
? ?? ? } else {
? ?? ?? ?? ?if (mCallback != null) {
? ?? ?? ?? ?? ? if (mCallback.handleMessage(msg)) {
? ?? ?? ?? ?? ?? ???return;
? ?? ?? ?? ?? ? }? ?? ?? ?? ?
? ?? ?? ???}? ?? ?? ?? ?
? ?? ?? ???handleMessage(msg);? ?? ?
? ?? ? }? ?
? ???}
Looper
Message放在消息队列里了,谁来一个一个的取出来处理呢?这时轮到Looper上场了,它的函数loop会一直循环处理队列中的消息,直到遇上一个没有target的Message:
public static final void loop() {
? ? Looper me = myLooper();
? ? MessageQueue queue = me.mQueue;
? ? while (true) {
? ?? ???Message msg = queue.next(); // might block
? ?? ???//if (!me.mRun) {
? ?? ???//? ? break;
? ?? ???//}
? ?? ???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);
? ?? ?? ?? ?if (me.mLogging!= null) me.mLogging.println(
? ?? ?? ?? ?? ?? ???"<<<<< Finished to? ? " + msg.target + " "
? ?? ?? ?? ?? ?? ???+ msg.callback);
? ?? ?? ?? ?msg.recycle();
? ?? ???}
? ? }
}
由此可见:一个Looper总是和一个MessageQueue关联起来的。
Thread
loop只是一个函数,它也需要别人来执行它。由于它一执行就会阻塞在那里,所以一定需要一个线程来调用:
??*??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();
??*? ?? ?}
??*??}
一个Looper也总是和一个Thread关联起来的,不过不一定要创建新线程,可以是主线程的。Handler和Thread不是一一对应的,理论上,在一个LooperThread中,可以有任何多个Handler,每个消息都可以指定不同的Handler,因为每个消息都可以有不同的行为。
在创建Handler时并不会创建Thread,它只是取当前线程的Looper的MessageQueue:
? ? public Handler() {
? ?? ???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 = null;
? ? }通过myLooper取出当前线程的Looper:
? ? public static final Looper myLooper() {
? ?? ???return (Looper)sThreadLocal.get();
? ? }这个Looper是在Looper.prepare里创建的:
? ? public static final void prepare() {
? ?? ???if (sThreadLocal.get() != null) {
? ?? ?? ?? ?throw new RuntimeException("Only one Looper may be created per thread");
? ?? ???}
? ?? ???sThreadLocal.set(new Looper());
? ? }
详细解决方案
Android中的MessageQueue,Handler,Looper跟Thread
热度:83 发布时间:2016-05-01 13:46:52.0
相关解决方案
- Exception in thread "main" org.hibernate.HibernateException: /hibernate.cfg.xml解决办法
- thread(线程)中用spring注入不成功有关问题
- Exception in thread "main" java.lang.UnsupportedClassVersionError:有关问题
- android 读取byte[]中的元素解决方案
- android 标题栏兑现方式
- android 中Activity向BroadcastReceiver发送数据,该怎么解决
- Android 4.0 为什么模拟器老是提示小弟我谷歌拼音输入法已停止
- android:getSharedPreferences() 这是哪个类的方法解决思路
- android 怎么判断一个程序是否联网
- Thread.sleep() 有关问题
- android 大量数据按周分组,该如何解决
- android RadioButton如何设置默认选中
- Exception in thread "main" java.lang.NullPointerException,该怎么处理
- 小弟我的程序中Exception in thread "main" java.lang.NullPointerException如何解决
- ksoap2-android-这个包,连接webService怎么设置超时
- Exception in thread "main" java.lang.UnsatisfiedLinkError: com.
- android 怎么重新设置锚点
- Exception in thread "main" java.lang.InstantiationError:
- Exception in thread "Thread-7" java.lang.UnsatisfiedLinkError:
- android UI界面设计解决方案
- android 图片对象获取的有关问题
- Exception in thread "main" java.lang.NoClassDefFound:HelloWorld,该怎么处理
- android 怎么调用淘宝支付宝接口
- Android 沿袭InputMethodService自定义输入法
- android 关于服务连接的疑义
- 这个是什么东东 Pool thread stack traces
- android 两个activity如何通信
- android 怎么实现对view的放大和缩小
- android 教程解决方法
- android ID,该如何处理