当前位置: 首页 > 科技观察

Handler、Looper和MessageQueue源码分析

时间:2023-03-18 11:11:40 科技观察

在Android中,Handler可以用来在主线程中更新UI变化。更新UI只能在主线程中更新。为了让其他线程能够控制UI的变化,Android提供了一种机制Handler、Looper和MessageQueue共同协作来达到其他线程更新UI的目的。一般我们会在主线程中通过如下方法定义一个HandlerprivateHandlermHandler=newHandler(){@OverridepublicvoidhandleMessage(Messagemsg){tv.setText("mHandlerchangeUI");super.handleMessage(msg);}};对于MessageQueue,它们在哪里被调用,它们是如何协作的呢?Looper不会在主线程中显式调用,而是在ActivityThread.main方法中默认调用。publicstaticvoidmain(String[]args){Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"ActivityThreadMain");SamplingProfilerIntegration.start();//CloseGuarddefaultstotrueandcanbequitespammy.We//disableithere,butselectivelyenableitlater(via//StrictMode)ondebugsbuilds,butusing.DropClose,notlogs.setEnabled(false);Environment.initForCurrentUser();//SetthereporterforeventlogginginlibcoreEventLogger.setReporter(newEventLoggingReporter());//MakesureTrustedCertificateStorelooksintherightplaceforCAcertificatesfinalFileconfigDir=Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setArgDirectory(setArgDirectory0);");Looper.prepareMainLooper();//创建LooperActivityThreadthread=newActivityThread();thread.attach(false);if(sMainThreadHandler==null){sMainThreadHandler=thread.getHandler();}if(false){Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG,"ActivityThread"));}//EndofeventActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();//开启Looper循环thrownewRuntimeException("Mainthreadloopunexpectedlyexited");}如上代码,调用Looper.prepareMainLooper()方法,在主线程中创建了一个Looper,不信我们看看这个方法做了什么null){thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");}sThreadLocal.set(newLooper(quitAllowed));//创建Looper并赋值给sThreadLocal}/***初始化当前线程为一个looper,标记为一个*application的mainlooper。你的application*的mainlooper是由Android环境创建的,所以你永远不需要*自己调用这个函数.参见:{@link#prepare()}*/publicstaticvoidprepareMainLooper(){prepare(false);synchronized(Looper.class){if(sMainLooper!=null){thrownewIllegalStateException("ThemainLooperh因为已经准备好了。”);}sMainLooper=myLooper();}}publicstatic@NullableLoopermyLooper(){returnsThreadLocal.get();}在prepareMainLooper方法中,调用了prepare,通过prepare,你会发现它实际上创建了一个Looper,并赋值给了sThreadLocal。同时可以通过myLooper方法获取当前线程。循环器。我们来看看newLooper(quitAllowed)初始化了什么privateLooper(booleanquitAllowed){mQueue=newMessageQueue(quitAllowed);mThread=Thread.currentThread();}这里终于看到了MessageQueue,它创建了一个MessageQueue。消息队列用于保存后续的消息。回到ActivityThread.main方法,发现它调用了Looper.loop()启动Looper循环,监听MessageQueue中的消息。loop我们看一下Looper.loop()的源码:");}finalMessageQueuequeue=me.mQueue;//获取消息队列//确保该线程的标识是本地进程的标识,//并跟踪该标识令牌实际是什么。Binder.clearCallingIdentity();finallongident=Binder.clearCallingIdentity();for(;;){Messagemsg=queue.next();/mightblockif(msg==null){//Nomessageindicatesthatthemessagequeueisquitting.return;}//这必须是本地变量,incaseaUIeventsetstheloggerfinalPrinterlogging=me.mLogging;if(logging!=null){logging.println(">>>>>Dispatchingto"+msg.target+""+msg.callback+":"+msg.what);}finallongtraceTag=me.mTraceTag;if(traceTag!=0){Trace.traceBegin(traceTag,msg.target.getTraceName(msg));}try{msg.target.dispatchMessage(msg);//通过Handler分发消息}finally{if(traceTag!=0){Trace.traceEnd(traceTag);}}if(logging!=null){logging.println("<<<<klass=getClass();if((klass.isAnonymousClass()||klass.isMemberClass()||klass.isLocalClass())&&(klass.getModifiers()&Modifier.STATIC)==0){Log.w(TAG,"下面的Handler类应该是staticorleaksmightoccur:"+klass.getCanonicalName());}}mLooper=Looper.myLooper();if(mLooper==null){thrownewRuntimeException("Can'tcreatehandlerinsidethreadthathasnotcalledLooper.prepare()");}mQueue=mLooper.mQueue;mCallback=callback;mAsynchronous=async;}通过Handler的初始化,获取到自己所在线程的Looper,同时也获取到Looper队列中的消息。当然,如果线程的Looper为空,就会抛出异常,这就解释了为什么在非主线程中创建Handler分别调用Looper.prepare和Looper.loop,而主线程不需要,因为它已被默认调用。向上。dispatchMessagepublicvoiddispatchMessage(Messagemsg){if(msg.callback!=null){handleCallback(msg);}else{if(mCallback!=null){if(mCallback.handleMessage(msg)){return;}}handleMessage(味精);}}privatestaticvoidhandleCallback(Messagemessage){message.callback.run();}回到前面,对于dispatchMessage的处理,首先判断msg.callback是否为空,这里的callback应该可以通过上面的Message,如果不为空,则直接调用Runnable的run方法。否则,调用Handler的handleMessage方法。这个方法相信大家都很熟悉,事件的处理都是在这个方法中执行的。因为我们已经知道Handler已经连接到了主线程,所以handleMessage中的处理自然是在主线程中进行,UI自然就可以更新了。通过这个,我们可以把Looper比作一座桥,连接Looper所在线程和Handler之间的通信,同时管理消息队列MessageQueue中的消息。那么前面的Runnable怎么不为空呢?我们使用Handler有两种方式,一种是直接创建一个Handler并重写它的handleMessage方法,另一种可以通过Handler.post(Runnable)来使用,这样事件处理就自然的在run方法中实现了。上面介绍了Handler如何与需要操作的线程取得联系,以及如何取消息和处理消息。下面说说Looper中消息是如何放入MessageQueue的。sendMessageAtTime通过Handler发送消息的方式有很多种,比如:sendMessage、sendEmptyMessage、sendMessageDelayed等,其实都是调用sendMessageAtTime方法直到结束。那么让我们看一下sendMessageAtTime方法中的实现。publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){MessageQueuequeue=mQueue;if(queue==null){RuntimeExceptione=newRuntimeException(this+"sendMessageAtTime()calledwithnomQueue");Log.w("Looper",e.getMessage(),e);returnfalse;}returnenqueueMessage(queue,msg,uptimeMillis);}和sendMessageAtTime调用了enqueueMessage操作,看方法名就知道是enqueue操作。enqueueMessageprivatebooleanenqueueMessage(MessageQueuequeue,Messagemsg,longuptimeMillis){msg.target=this;if(mAsynchronous){msg.setAsynchronous(true);}returnqueue.enqueueMessage(msg,uptimeMillis);}正如预期的那样,queue.msgqueueMessage(,uptimeMillis)到将消息添加到消息队列中,这段代码msg.target=this将当前的Handler赋值给msg.target,也就是前面提到的Looper.loop方法中调用的Handler。这样就把消息放到了MessageQueue中,然后通过上面提到的循环把消息取出来进行相应的处理,这样就形成了整个处理消息的系统。这也是Handler内部发生的事情。好了,Handler、Looper和MessageQueue的联系基本就这些了。我也简单的画了一张图,希望能帮助总结一下他们之间的过程。首先创建一个Handler,在Handler所在的线程中必须有一个Looper。如果在主线程中默认为我们实现,其他线程必须调用Looper.prepare创建一个Looper并调用Looper.loop开始处理消息。每个Looper都有一个MessageQueue,用来存放Message。Handler通过post或send..等一系列操作通过Looper将消息放入消息队列,Looper不断开启***循环监听消息的处理,不断从MessageQueue中取出消息,并递交它们交给当前Looper绑定的handler的dispatchMessage进行分发,最后根据情况调用Runnable的run或Handler的HandlerMessage方法激活消息处理。其他分享:https://idisfkj.github.io/arc...