Handler机制原理
首先说说Handler 使用中隐藏的坑
1、delay的时间过长,导致 activity未被回收内存泄漏以及逻辑错误
可以将Handler携程static静态内部类,或者而降handler中引用的activity位软引用
2、new 了过多的message,导致内存泄漏,应该在处理后remove这些msg
3、Activity finish()后应该remove所有的msg和runable
------------------------------------------------------------------------------------------------------------------------------
各种类的含义
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
------------------------------------------------------------------------------------------------------------------------------
关系
Handler,Looper和MessageQueue就是简单的三角关系。
Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。
而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。
这样说来,多个Handler都可以共享同一Looper和MessageQueue了。
这些Handler也就运行在同一个线程里,每个线程一个Loop而 一个MessageQueue。
------------------------------------------------------------------------------------------------------------------------------------------------------------
使用:
子线程网主线程中发消息,直接在主线程中handler = new Handler(),子线程中可以直接用handler.sendmessage。。。
主线程网子线程中,Looper.prepare()... handler = new Handler()... looper.loop...然后handler.sendmessage
一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱
Handler的处理过程运行在创建Handler的线程里
· 一个Looper对应一个MessageQueue
· 一个线程对应一个Looper
· 一个Looper可以对应多个Handler
· 不确定当前线程时,更新UI时尽量调用post方法
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Android的主线程循环创建
Android程序的运行入口点可以认为是android.app.ActivityThread类的main()方法(源码2.3.3):
public static final void main(String[] args) { // other codes... // 创建主线程循环 Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); // other codes... // 进入当前线程(此时是主线程)消息循环 Looper.loop(); // other codes... thread.detach(); // other codes... }
这个main()方法里面为程序创建了主线程循环。
Looper类中的主线程创建方法prepareMainLooper():
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
今天用子线程调Toast报了一个Can't create handler inside thread that has not calledLooper.prepare()错误。
解决办法很简单:
Looper.prepare();
new handler...
Looper.loop();
Looper
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper()); //在当前线程中创建一个Looper
}
private Looper() {
mQueue = new MessageQueue(); //关键在这,创建Looper都干了什么。 其实是创建了消息队列
mRun = true;
mThread = Thread.currentThread();
}
一般如果不是在主线程中又开启了新线程的话,一般都会碰到这个问题。
原因是在创建新线程的时候默认情况下不会去创建新的MessageQueue。