Android基础之Handler理解
1.Handler: 用于线程之间的通信,是一种异步回调机制.
2.Handler内部实现主要涉及到Looper,Message,MessageQueue以及Thread类.
Handler: 发送消息和接收处理消息
Message: 消息载体
MessageQueue: 消息队列,存放发送的消息,内部使用单链表结构.
Looper: 轮询器,从消息队列里面循环获取消息,有消息立即处理,没有消息就会阻塞,等待消息到来.
Thread :线程,每一个线程最多只允许一个Looper.
3.流程可以总结为:
调用Looper.prepare方法,创建Looper对象,Looper的构造方法中会创建一个MessageQueue,同时将looper绑定 到当前线程.
创建Handler的时候,其构造方法里会获取到当前线程的Looper对象,并获取到该looper绑定的消息队列,messagequeue;当调用sendmessage()的时候其底层实际上调用了enqueuemessage方法,该方法主要做了两步,第一步是msg.target= this,也就是指向当前handler;第二步是,调用了ueue.enqueueMessage(msg, uptimeMillis);方法,将消息插入到当前线程的消息队列.
Looper.loop方法,会循环的从messagequeue读取消息,并调用msg.target.dispatchmessage(msg)方法分发消息.,上面可以知道msg.target其实就是当前线程的handler,所以其实就是调用了handler的dispatchmessage方法,交给handlemessag处理.
现在我们来思考几个问题
1.上面说了,轮询器去读取消息是循环读取,这是一个死循环,为什么我们的程序没有卡死呢?
答; ui线程,也就是我们说的主线程,也被称作ActivityThread,默认初始化了Looper,这也是我们可以使用handler的原因.我们知道线程是一段可执行的代码,代码执行完毕,线程生命周期也就结束了,步入死亡;ui线程也就是main线程如果也是这样执行结束就死亡肯定不是我们期望的结果,所以如果我们想要将线程一直执行下午,那么最简单的做法就是让代码一直执行下去,而死循环便能保证不会退出.当然这里不是简单的死循环,没有消息的时候会进行休眠,让出cpu,这样我们的程序就不会卡死.;这里既然是死循环,那么其他事务是如何处理的呢?其实我们看源码会知道,有一个thread.attach(false),创建了新的线程去处理.真正会卡死主线程的操作是在回调方法 onCreate/onStart/onResume 等操作时间过长,会导致掉帧,甚至发生 ANR,looper.loop 本身不会导致应用卡死。
2.Handler是如何 能线程切换呢?
答: 首先我们要知道线程是共享资源的,所以 Handler 处理不同线程问题就只要注意异步情况即可。Handler 创建的时候会采用当前线程的 Looper 来构造消息循环系统,Looper 在哪个线程创建,就跟哪个线程绑定,并且Handler 是在他关联的 Looper 对应的线程中处理消息的.
3.系统为什么不允许在子线程中访问UI?
这是因为 Android 的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态,那么为什么系统不对UI控件的访问加上锁机制呢?缺点有两个:
①首先加上锁机制会让UI访问的逻辑变得复杂
②锁机制会降低UI访问的效率,因为锁机制会阻塞某些线程的执行。
所以最简单且高效的方法就是采用单线程模型来处理UI操作。
那么子线程一定不能更新UI吗?
答:当然是可以的,我们可以使用Handler来完成;也可以使用 Activity 对象的 runOnUiThread 方法。
4.那为什么我们在子线程中使用toast和dialog会报错呢?
答:直接调用会报错,提示需要使用loopprepare和looper.loop方法(但是不建议这么做,因为它会使线程无法执行结束,导致内存泄露)
5.如何处理Handler 使用不当导致的内存泄露?
答: 上文内存泄漏的我们讲过,使用handler可能会导致内存泄漏,譬如,延迟发送消息,Activity销毁但是消息还没执行,另外就是handler若是使用到了context传入了Actiity也会导致出现内存泄漏的问题.
解决办法: 1.有延时消息,要在 Activity 销毁的时候移除 Messages
2. 匿名内部类导致的泄露改为匿名静态内部类,并且对上下文或者 Activity 使用弱引用。.
本文参考文章: https://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650241824&idx=1&sn=aa4be9ab94828bfff4ee9108a85a0f0b&chksm=88638a4fbf1403594b7e2e0fc04a30ced3ec7819cc891b4e872b52e29692b9f7a11a8658a97d&mpshare=1&scene=23&srcid=1117IBUFS6V6EDHPf0emAMs3#rd
有兴趣的话可以看下源码;
private static void prepare(booleanquitAllowed){// 创建一个Looper对象
if(sThreadLocal.get() !=null) {// 每个线程只允许有一个looper
thrownewRuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(newLooper(quitAllowed));
}
// 看下Looper的构造方法
private Looper(boolean quitAllowed){
mQueue =newMessageQueue(quitAllowed);// new了一个消息队列
mThread = Thread.currentThread(); // 绑定到当前线程
}
// Looper.loop()方法,循环从消息队列中读取消息,并且分发消息
public static void loop(){
//myLooper方法会从ThreadLocal中获取到当前线程的Looper
finalLooper me = myLooper();
if(me ==null) {// 若获取不到looper对象
thrownewRuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for(;;) {//循环的去MessageQueue中读取消息
Message msg = queue.next();
if(msg ==null) {
return;
}
Printer logging = me.mLogging;
if(logging !=null) {
logging.println(">>>>> Dispatching to "+ msg.target +" "+ msg.callback +": "+ msg.what);
}//调用发送该消息的Handler的dispatchMessage方法处理该消息
//这里的msg.target == Handler,是在Handler发送消息的时候进行赋值的
msg.target.dispatchMessage(msg);
if(logging !=null) {
logging.println("<<<<< Finished to "+ msg.target +" "+ msg.callback);
}
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.recycleUnchecked();
}
Handler的构造方法
public Handler(
Callback callback,booleanasync){
if(FIND_POTENTIAL_LEAKS) {
finalClass 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());
}
}
//获取当前线程中的Looper
mLooper = Looper.myLooper();
if(mLooper ==null) {
//如果当前线程没有Looper就会抛出异常。
thrownewRuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
}
//获取Looper中的MessageQueue,可以看出,Looper中为每个线程维护了一个Message
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
//Handler发送消息的方法,追踪senndmessage到最底层的方法就是enqueueMessage。
private boolean enqueueMessage(MessageQueue queue, Message msg,longuptimeMillis){
msg.target =this;
if(mAsynchronous) {
msg.setAsynchronous(true);
}
returnqueue.enqueueMessage(msg, uptimeMillis);
}