Android消息机制基于源码解析分析.docx
- 文档编号:23383398
- 上传时间:2023-05-16
- 格式:DOCX
- 页数:22
- 大小:53.68KB
Android消息机制基于源码解析分析.docx
《Android消息机制基于源码解析分析.docx》由会员分享,可在线阅读,更多相关《Android消息机制基于源码解析分析.docx(22页珍藏版)》请在冰豆网上搜索。
Android消息机制基于源码解析分析
Android消息机制(基于源码解析)
1.消息机制概述
Android中的消息机制主要指的是Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper、Message的支撑,下文会逐一分析。
2.为什么需要消息机制
Android中的消息机制主要是为了满足线程间通信而设计的,最重要的应用场景应该在于更新UI
Android规定访问UI只能在主线程中进行,如果在子线程中访问UI,那么程序就会抛出异常
系统为什么不允许在自线程中访问UI呢?
这是因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。
那为什么不对UI控件的访问加上锁机制呢?
缺点有两个:
首先加上锁机制会让UI访问的逻辑变得复杂;
其次锁机制会降低访问UI的效率,因为锁机制会阻塞某些现成的执行
鉴于这两个缺点,最简单且最高效的方法就是采用单线程模型来处理UI操作,对于开发者来说也不是很麻烦,只是需要通过Handler切换下UI的访问执行线程即可
3.Android中线程的分类
带有消息队列,用来执行循环型任务(例如主线程ActivityThread,Android.os.HandlerThread)有消息时就处理,没有消息时就睡眠
没有消息队列,用来执行一次性任务(例如java.lang.Thread)
任务一旦执行完成便退出
4.带有消息队列的线程具体实现
主要涉及4个方面
Message(消息)
MessageQueue(消息队列)
Looper(消息循环)
Handler(消息发送和处理)
4.1消息队列
说到MessageQueue,我们来看下它是干什么的
/**
*Low-levelclassholdingthelistofmessagestobedispatchedbya
*{@linkLooper}.MessagesarenotaddeddirectlytoaMessageQueue,
*butratherthrough{@linkHandler}objectsassociatedwiththeLooper.
*
*YoucanretrievetheMessageQueueforthecurrentthreadwith
*{@linkLooper#myQueue()Looper.myQueue()}.
*/
它是一个低等级的持有Messages集合的类,被Looper分发。
Messages并不是直接加到MessageQueue的,而是通过Handler对象和Looper关联到一起。
我们可以通过Looper.myQueue()方法来检索当前线程的MessageQueue。
4.2Message
在整个消息处理机制中,message又叫task,封装了任务携带的信息和处理该任务的handler。
我们看下这个类的注释
/**
*
*Definesamessagecontainingadescriptionandarbitrarydataobjectthatcanbe
*senttoa{@linkHandler}.Thisobjectcontainstwoextraintfieldsandan
*extraobjectfieldthatallowyoutonotdoallocationsinmanycases.
*
*WhiletheconstructorofMessageispublic,thebestwaytoget
*oneoftheseistocall{@link#obtainMessage.obtain()}oroneofthe
*{@linkHandler#obtainMessageHandler.obtainMessage()}methods,whichwillpull
*themfromapoolofrecycledobjects.
*/
这个类定义了一个包含描述和一个任意类型对象的对象,它可以被发送给Handler。
从注释里我们还可以了解到以下几点:
尽管Message有public的默认构造方法,但是你应该通过Message.obtain()来从消息池中获得空消息对象,以节省资源。
如果你的message只需要携带简单的int信息,请优先使用Message.arg1和Message.arg2来传递信息,这比用Bundle更省内存
用message.what来标识信息,以便用不同方式处理message
4.3Looper
/*
*Thisclasscontainsthecoderequiredtosetupandmanageaneventloop
*basedonMessageQueue.APIsthataffectthestateofthequeueshouldbe
*definedonMessageQueueorHandlerratherthanonLooperitself.Forexample,
*idlehandlersandsyncbarriersaredefinedonthequeuewhereaspreparingthe
*thread,looping,andquittingaredefinedonthelooper.
*/
这个类是基于消息队列用来设置和管理事件循环的代码,对队列的改变应该在MessageQueue或Handler上定义,而不是在Looper本身定义,例如空间处理和同步障碍应该在队列上定义,然而准备线程、循环和退出在Looper本身定义,
4.4Handler
/**
*AHandlerallowsyoutosendandprocess{@linkMessage}andRunnable
*objectsassociatedwithathread’s{@linkMessageQueue}.EachHandler
*instanceisassociatedwithasinglethreadandthatthread’smessage
*queue.WhenyoucreateanewHandler,itisboundtothethread/
*messagequeueofthethreadthatiscreatingit–fromthatpointon,
*itwilldelivermessagesandrunnablestothatmessagequeueandexecute
*themastheycomeoutofthemessagequeue.
*
*
TherearetwomainusesforaHandler:
(1)toschedulemessagesand
*runnablestobeexecutedassomepointinthefuture;and
(2)toenqueue
*anactiontobeperformedonadifferentthreadthanyourown.
*
*
Schedulingmessagesisaccomplishedwiththe
*{@link#post},{@link#postAtTime(Runnable,long)},
*{@link#postDelayed},{@link#sendEmptyMessage},
*{@link#sendMessage},{@link#sendMessageAtTime},and
*{@link#sendMessageDelayed}methods.Thepostversionsallow
*youtoenqueueRunnableobjectstobecalledbythemessagequeuewhen
*theyarereceived;thesendMessageversionsallowyoutoenqueue
*a{@linkMessage}objectcontainingabundleofdatathatwillbe
*processedbytheHandler’s{@link#handleMessage}method(requiringthat
*youimplementasubclassofHandler).
*
*
WhenpostingorsendingtoaHandler,youcaneither
*allowtheitemtobeprocessedassoonasthemessagequeueisready
*todoso,orspecifyadelaybeforeitgetsprocessedorabsolutetimefor
*ittobeprocessed.Thelattertwoallowyoutoimplementtimeouts,
*ticks,andothertiming-basedbehavior.
*
*
Whena
*processiscreatedforyourapplication,itsmainthreadisdedicatedto
*runningamessagequeuethattakescareofmanagingthetop-level
*applicationobjects(activities,broadcastreceivers,etc)andanywindows
*theycreate.Youcancreateyourownthreads,andcommunicatebackwith
*themainapplicationthreadthroughaHandler.Thisisdonebycalling
*thesamepostorsendMessagemethodsasbefore,butfrom
*yournewthread.ThegivenRunnableorMessagewillthenbescheduled
*intheHandler’smessagequeueandprocessedwhenappropriate.
*/
这个有点长,简单概括下:
每一个Handler实例关联了一个单一的ghread和这个thread的messagequeue,当Handler的实例被创建的时候它就被绑定到了创建它的thread。
它用来调度message和runnables在未来某个时间点的执行,还可以排列其他线程里执行的操作。
Handler主要用的来管理某个线程(也可能是进程)的消息队列。
比如处理主线程的消息队列,包含消息的发送和接收过程。
消息的发送可以通过Post的一系列方法和Sende的一系列方法来实现。
而post的一系列方法最终是通过send的一系列方法来实现的。
这样就可以将一些耗时任务放到其他线程之中,待任务完成之后就往主线程的消息队列中添加一个消息,这样Handler的Callback,即handleMessage就会被调用。
但是Handler并不是线程安全的,因此建议将Handler作为一个静态内部类。
所以Handler只是处理消息,耗时任务放在其他线程。
4.5四元素的交互过程
具体工作过程
消息队列的创建
消息循环
消息的发送最基本的两个API
带一个Runnable参数,会被转换为一个Message参数
带一个Message参数,用来描述消息的内容
Handler.sendMessage
Handler.post
消息的处理
基于消息的异步任务接口
android.os.HandlerThread
适合用来处于不需要更新UI的后台任务
android.os.AyncTask
适合用来处于需要更新UI的后台任务
4.5.1Looper与消息队列的创建
首先确认当前线程是否具有Looper(主线程默认具有Looper)如果没有则创建
我们知道Android上一个应用的入口,应该是ActivityThread。
和普通的Java类一样,入口是一个main方法。
创建主线程源码示例:
publicstaticvoidmain(String[]args){
//~省略部分无关代码~
//创建Looper和MessageQueue对象,用于处理主线程的消息
Looper.prepareMainLooper();
//创建ActivityThread对象
ActivityThreadthread=newActivityThread();
//建立Binder通道(创建新线程)
thread.attach(false);
if(sMainThreadHandler==null){
sMainThreadHandler=thread.getHandler();
}
if(false){
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG,"ActivityThread"));
}
//EndofeventActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//消息循环运行
Looper.loop();
thrownewRuntimeException("Mainthreadloopunexpectedlyexited");
}
我们可以看到主方法首先通过Looper.prepareMainLooper()初始化了我们主线程(UI)的Looper并且启动它。
然后就可以处理子线程和其他组件发来的消息了
如果不是主线程的两线程进行通信,可以通过以下方式来创建
classLooperThreadextendsThread{
publicHandlermHandler;
publicvoidrun(){
//将当前线程初始化为Looper线程
Looper.prepare();
//...其他处理,如实例化handler
mHandler=newHandler(){
publicvoidhandleMessage(Messagemsg){
//processincomingmessageshere
}
};
//开始循环处理消息队列
Looper.loop();
}
}
Looper源码如下:
publicfinalclassLooper{
privatestaticfinalStringTAG="Looper";
//sThreadLocal.get()willreturnnullunlessyou'vecalledprepare().
staticfinalThreadLocal
privatestaticLoopersMainLooper;//guardedbyLooper.class
//Looper内的消息队列
finalMessageQueuemQueue;
//当前线程
finalThreadmThread;
privatePrintermLogging;
privateLooper(booleanquitAllowed){
mQueue=newMessageQueue(quitAllowed);
mThread=Thread.currentThread();
}
/**Initializethecurrentthreadasalooper.
*Thisgivesyouachancetocreatehandlersthatthenreference
*thislooper,beforeactuallystartingtheloop.Besuretocall
*{@link#loop()}aftercallingthismethod,andenditbycalling
*{@link#quit()}.
*/
publicstaticvoidprepare(){
prepare(true);
}
privatestaticvoidprepare(booleanquitAllowed){
//试图在有Looper的线程中再次创建Looper将抛出异常
if(sThreadLocal.get()!
=null){
thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");
}
sThreadLocal.set(newLooper(quitAllowed));
}
/**
*Initializethecurrentthreadasalooper,markingitasan
*application'smainlooper.Themainlooperforyourapplication
*iscreatedbytheAndroidenvironment,soyoushouldneverneed
*tocallthisfunctionyourself.Seealso:
{@link#prepare()}
*/
publicstaticvoidprepareMainLooper(){
prepare(false);
synchronized(Looper.class){
if(sMainLooper!
=null){
thrownewIllegalStateException("ThemainLooperhasalreadybeenprepared.");
}
sMainLooper=myLooper();
}
}
//~省略部分无关代码~
}
从中我们可以看到以下几点:
prepare()其核心就是将looper对象定义为ThreadLocal
一个Thread只能有一个Looper对象
prepare()方法会调用Looper的构造方法,初始化一个消息队列,并且指定当前线程
ThreadLocal并不是一个Thread,而是Thread的局部变量。
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本。
所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。
在调用Looper.loop()方法之前,确保已经调用了prepare(booleanquitAllowed)方法,并且我们可以调用quite方法结束循环
接下来再看看Looper.loop()
/**
*Runthemessagequeueinthisthread.Besuretocall
*{@link#quit()}toendtheloop.
*/
publicstaticvoidloop(){
//得到当前线程Looper
finalLooperme=myLooper();
if(me==null){
thrownewRuntimeException("NoLooper;Looper.prepare()wasn'tcalledonthisthread.");
}
//得到当前looper的MessageQueue
finalMessageQueuequeue=me.mQueue;
//Makesuretheidentityofthisthreadisthatofthelocalprocess,
//andkeeptrackofwhatthatidentitytokenactuallyis.
Binder.clearCallingIdentity();
finallongident=Binder.clearCallingIdentity();
//开始循环
for(;;){
Messagemsg=queue.next();//mightblock
if(msg==null){
//Nomessageindicatesthatthemessagequeueisquitting.
//没有消息表示消息队列正在退出
return;
}
//Thismustbeinalocalvariable,incaseaUIeventsetsthelogger
Printerlogging=me.mLogging;
if(logging!
=null){
logging.println(">>>>>Dispatchingto"+msg.target+""+
msg.callback+":
"+msg.what);
}
//将真正的处理工作交给message的target,即handler
msg.target.dispatchMessage(msg);
if(logging!
=null){
logging.println("<<<<
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 消息 机制 基于 源码 解析 分析
![提示](https://static.bdocx.com/images/bang_tan.gif)