-
Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃。
-
Android子线程中创建Handler,需要在new Handler前Looper.prepare() ,否则会崩溃。
-
每个线程只能Looper.prepare() 一次,每个线程中最多只会有一个Looper对象,否则会报错。
-
没Looper.prepare() 报错的原因是Handler的构造函数中调用了Looper.myLooper()获取Looper,而Looper的值在Looper.prepare() 时设置,没有设置Looper在new Handler中获取的为null,所以报错。
-
主线程中的Handler也没有调用Looper.prepare()方法不报错的原因是,在程序启动的时候,系统已经帮我们自动调用了Looper.prepare()方法。
//启动程序主线程,关注Looper.prepareMainLooper() public static void main(String[] args) { SamplingProfilerIntegration.start(); CloseGuard.setEnabled(false); Environment.initForCurrentUser(); EventLogger.setReporter(new EventLoggingReporter()); Process.setArgV0("
"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } //Looper.prepareMainLooper()中prepare()与setMainLooper public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); if (Process.supportsProcesses()) { myLooper().mQueue.mQuitAllowed = false; } } -
Handler传递消息用的Message对象,最终是通过传入Handler的sendMessageAtTime(Message msg, long uptimeMillis)方法来传递的;在该方法中,msg会被加入MessageQueue 消息队列,调用的是enqueueMessage方法
-
MessageQueue并没有使用一个集合把所有的消息都保存起来,它只使用了一个mMessages对象表示当前待处理的消息。
-
MessageQueue所谓的入队其实就是将所有的消息按时间来进行排序,这个时间当然就是我们刚才介绍的uptimeMillis参数。具体的操作方法就根据时间的顺序调用msg.next,从而为每一个消息指定它的下一个消息是什么,我理解为相当于数据结构中的链表结构。
final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.target == null) { mQuiting = true; } msg.when = when; Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; this.notify(); } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; this.notify(); } } return true; }
-
在loop()方法中,通过调用的MessageQueue的next()方法让消息出队列,该方法会取出当前Message,并且将方法中的mMessages替换为下一条消息。
-
在loop()方法中如果没有下一条Message,会阻塞,直到有新的消息入队列。
-
最终的回调函数handleMessage能取得Message也是在next()方法后,回调传入的,在之前的出入队列时,Handler对象也是被保存在Message.target中的,所以才能回调。
-
以下是盗的图解:
-
Looper主要作用: 1、 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。 2、 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
-
Handler的处理: 1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。 2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。 3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue相关联。 4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。 5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
-
笔记阅读/参考内容: CSDN博主「鸿洋_」的文章 CSDN博主「guolin_」的文章
版权归属:
eoser
许可协议:
本文使用《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》协议授权
评论区