handler是什么?
handler是Android提供用来更新UI的一套消息机制,也是一套消息处理的机制(发送和处理消息)
handler原理
handler负责消息发送,looper负责接收handler发送过来的消息,并把消息发送给handler,messageQueue存储消息的容器
这里先说明一下ThreadLocal,主要在线程中保存变量信息,主要有两个比较重要的方法,一个是get方法,一个是set方法
publicvoidset(Tvalue){Thread currentThread=Thread.currentThread();Values values=values(currentThread);if(values==null){values=initializeValues(currentThread);}values.put(this,value);}image.gif
set方法设置当前线程的值,使用键值对的形式存储Thread和looper之间的关系,Thread作为key,looper作为value
publicTget(){// Optimized for the fast path.Thread currentThread=Thread.currentThread();Values values=values(currentThread);if(values!=null){Object[]table=values.table;int index=hash&values.mask;if(this.reference==table[index]){return(T)table[index+1];}}else{values=initializeValues(currentThread);}return(T)values.getAfterMiss(this);}image.gif
get方法就是取出当前线程对应的looper,也就是说ThreadLocal是负责thread和looper之间的关系的
下面看一下Looper.prepare()方法
privatestaticvoidprepare(boolean quitAllowed){if(sThreadLocal.get()!=null){thrownewRuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(newLooper(quitAllowed));}默认情况下ThreadLocal是没有存储的,所以要创建一个新的looperprivateLooper(boolean quitAllowed){mQueue=newMessageQueue(quitAllowed);mThread=Thread.currentThread();}image.gif
默认情况下ThreadLocal是没有存储的,所以要创建一个新的looper
privateLooper(boolean quitAllowed){mQueue=newMessageQueue(quitAllowed);mThread=Thread.currentThread();}image.gif
从looper方法中,创建了一个MessageQueue,在looper中维护着一个消息队列
知道了looper和MessageQueue之后,究竟handler跟这两者有什么关系呢,继续看源码
publicHandler(Callback callback,booleanasync){if(FIND_POTENTIAL_LEAKS){final Class<?extendsHandler>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){thrownewRuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}mQueue=mLooper.mQueue;mCallback=callback;mAsynchronous=async;}image.gif
首先调用Looper.myLooper()
publicstatic@Nullable LoopermyLooper(){returnsThreadLocal.get();}image.gif
获得当前的looper对象,通过looper拿到MessageQueue,就完成了handler和looper之间的关联
下面继续看handler的消息发送
publicbooleansendMessageAtTime(Message msg,long uptimeMillis){MessageQueue queue=mQueue;if(queue==null){RuntimeException e=newRuntimeException(this+" sendMessageAtTime() called with no mQueue");Log.w("Looper",e.getMessage(),e);returnfalse;}returnenqueueMessage(queue,msg,uptimeMillis);}image.gif
先获得当前的消息队列,如果队列为空就抛出异常,不为空,向消息队列中插入消息
privatebooleanenqueueMessage(MessageQueue queue,Message msg,long uptimeMillis){msg.target=this;if(mAsynchronous){msg.setAsynchronous(true);}returnqueue.enqueueMessage(msg,uptimeMillis);}image.gif
插入消息之前就指定消息发送给谁(msg.target),默认情况下发送给自己的handler,然后把消息放入队列中,handler就完成了发送message到MessageQueue的过程
那么消息又是如何轮询的呢?
publicstaticvoidloop(){final Looper me=myLooper();if(me==null){thrownewRuntimeException("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 blockif(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 loggerPrinter 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.recycleUnchecked();}}image.gif
通过myLooper()方法获取当前looper,进而获得当前的消息队列,然后通过MessageQueue的next方法获取消息,消息为空时返回,不为空时,调用handler的dispatchMessage(msg)方法,然后这个过程一直循环
publicvoiddispatchMessage(Message msg){if(msg.callback!=null){handleCallback(msg);}else{if(mCallback!=null){if(mCallback.handleMessage(msg)){return;}}handleMessage(msg);}}image.gif
首先查看msg.callback是否为空,不为空时去调用handleCallback(msg),这个方法在handler的构造方法中存在,可以实现消息的拦截;为空只就
调用handleMessage(msg),这个方法都是大家熟悉的,不在描述,整体的handler的原理就描述到这。
总结
handler在Android中扮演的非常重要的角色,熟悉handler的原理,不仅在面试的时候有用,就连activity的生命周期也是通过handler发送消息,详细请看Framewrok源码。
很多人都没有Framewrok源码这方面的资料,这里我整理了一份《Android Framework源码开发揭秘》分享给大家!
由于文档内容过多,因此为了避免影响到大家的阅读体验,在此只以截图展示部分内容,详细完整版的看文末有免费的获取方式!(文末还有使用ChatGPT机器人小福利哦!!大家不要错过)
《Android Framework源码开发揭秘》
本学习手册深入剖析了Android系统源代码,详细讲解了Android框架初始化过程及主要组件的工作原理,旨在通过实例和案例介绍 Android Framework 的核心概念和技术,从而帮助开发者更好地理解 Android 应用程序的设计和开发。
该手册适合具有一定 Android 应用开发经验的程序员,希望能通过深入学习 Android Framework 来帮助开发者更好地理解和掌握这一技术。
第一章 系统启动流程分析
Android系统完整的启动过程,从系统层次角度可分为 Linux 系统层、Android 系统服务层、Zygote进程模型三个阶段;
知识要点:
第一节 Android启动概括、
第二节 init.rc解析、
第三节 Zygote、
第四节 面试题
第二章 跨进程通信IPC解析
Binder作为Android进程间通信的机制,可以看做是一个驱动。在Android中,常见的进程间通信例如系统类的:打电话、闹钟等;自己创建的:像WebView、视频播放、音频播放、大图浏览等。
第三章 Handler源码解析
第一节 源码分析
第二节 难点问题
第三节Handler常问面试题
有需要的朋友扫描下方二维码领取!!!!
同时这里还搭建了一个基于chatGPT的微信群聊机器人,24小时为大家解答疑难技术问题。