Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx

上传人:b****5 文档编号:6858462 上传时间:2023-01-11 格式:DOCX 页数:21 大小:98.13KB
下载 相关 举报
Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx_第1页
第1页 / 共21页
Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx_第2页
第2页 / 共21页
Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx_第3页
第3页 / 共21页
Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx_第4页
第4页 / 共21页
Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx

《Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx》由会员分享,可在线阅读,更多相关《Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx(21页珍藏版)》请在冰豆网上搜索。

Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx

Android开发Handler异步通信机制全面解析包含LooperMessageQueue

Android开发:

Handler异步通信机制全面解析(包含Looper、MessageQueue)

定义

Android提供的一套消息传递机制

作用

用于实现子线程对UI线程的更新,实现异步消息的处理:

-在新启动的线程中发送消息

-在主线程中获取并处理信息

为什么要用Handler

在安卓开发中:

-为了保证Android的UI操作是线程安全的,Android规定了只允许UI线程修改Activity里的UI组件;

-但在实际开发中,必然会用到多个线程并发操作UI组件,这又将导致UI操作的线程不安全

所以问题在于:

如何同时满足:

-保证线程安全

-使多个线程并发操作UI组件

Handler消息传递机制就是解决这个问题的。

相关概念

主线程(UI线程)

-定义:

当程序第一次启动时,Android会同时启动一条主线程(MainThread)

-作用:

主线程主要负责处理与UI相关的事件,所以主线程又叫UI线程

子线程则负责一些比较耗时的操作(联网、取数据、SD卡数据加载等操作),而主线程和子线程之间的通信,就是要靠Handler了。

Message

-定义:

消息,理解为线程间通讯的数据单元(Handler接受和处理的消息对象。

例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程

MessageQueue

-定义:

消息队列

-作用:

用来存放通过Handler发过来的消息,按照先进先出执行

Handler

-定义:

Handler是Message的主要处理者

-作用:

负责将Message添加到消息队列&处理Looper分派过来的Message

Looper

-定义:

循环器,扮演MessageQueue和Handler之间桥梁的角色

作用:

主要负责消息循环:

循环取出MessageQueue的Message;消息派发:

将取出的Message交付给相应的Handler

每个线程中只能拥有一个Looper,但是一个Looper可以和多个线程的Handler绑定起来,也就是说很多个线程可以往一个Looper所持有的MessageQueue中发送消息。

这就给我们提供了线程之间通信的可能。

Handler在创建的时候可以显示指定Looper,这样在Handler在调用sendMessage()投递消息的时候会将消息添加到指定的Looper里面的MessageQueue。

如果不指定Looper,Handler默认绑定的是创建它的线程的Looper。

Handler异步通信机制工作流程图

!

[Handler异步通信传递机制流程图](

Handler、Looper、MessageQueue关系类图

!

[](**Handler**-提供sendMessage方法,将消息放置到队列中-提供handleMessage方法,定义个各种消息的处理方式;**Looper**-Looper.prepare():

实例化Looper对象;为当前线程生成一个消息队列;-Looper.loop():

循环从消息队列中获取消息,交给Handler处理;此时线程处于无限循环中,不停的从MessageQueue中获取Message消息;如果没有消息就阻塞**MessageQueue**-提供enqueueMessage方法,将消息根据时间放置到队列中;-提供next方法,从队列中获取消息,没有消息的时候阻塞;**Handler工作流程解释**异步通信传递机制步骤主要包括异步通信的准备、消息发送、消息循环和消息处理

异步通信的准备

包括Looper对象的创建&实例化、MessageQueue队列的创建和Handler的实例化

消息发送

Handler将消息发送到消息队列中

消息循环

Looper执行Looper.loop()进入消息循环,在这个循环过程中,不断从该MessageQueue取出消息,并将取出的消息派发给创建该消息的Handler

消息处理

调用该Handler的dispatchMessage(msg)方法,即回调handleMessage(msg)处理消息

好像很复杂?

那就先看下这个简图了解下:

!

[](

工作流程详细讲解

由上面可以得知,整个异步消息传递机制主要包括Handler、Looper和MessageQueue,接下来通过相应源码来解析这三部分

第一部分:

Looper

Looper主要负责:

1.自身的创建&创建MessageQueue2.消息循环(消息取出、派发)对应职责我们来看下相应的源码:

1.自身的创建&创建MessageQueue:

prepare()方法

publicstaticfinalvoidprepare(){

//判断sThreadLocal是否为null,否则抛出异常

//即Looper.prepare()方法不能被调用两次

//也就是说,一个线程中只能对应一个Looper实例

if(sThreadLocal.get()!

=null){

thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");

}

//sThreadLocal是一个ThreadLocal对象,用于在一个线程中存储变量

//实例化Looper对象并存放在ThreadLocal

//这说明Looper是存放在Thread线程里的

sThreadLocal.set(newLooper(true));

}

//再来看下Looper的构造方法

privateLooper(booleanquitAllowed){

//创建了一个MessageQueue(消息队列)

//这说明,当创建一个Looper实例时,会自动创建一个与之配对的MessageQueue(消息队列)

mQueue=newMessageQueue(quitAllowed);

mRun=true;

mThread=Thread.currentThread();

}

**2.消息循环:

loop()方法**

publicstaticvoidloop(){

//myLooper()方法作用是返回sThreadLocal存储的Looper实例,如果me为null,loop()则抛出异常

//也就是说loop方法的执行必须在prepare方法之后运行

//也就是说,消息循环必须要先在线程当中创建Looper实例

finalLooperme=myLooper();

if(me==null){

thrownewRuntimeException("NoLooper;Looper.prepare()wasn'tcalledonthisthread.");

}

//获取looper实例中的mQueue(消息队列)

finalMessageQueuequeue=me.mQueue;

Binder.clearCallingIdentity();

finallongident=Binder.clearCallingIdentity();

//进入消息循环

for(;;){

//next()方法用于取出消息队列里的消息

//如果取出的消息为空,则线程阻塞

Messagemsg=queue.next();//mightblock

if(msg==null){

return;

}

Printerlogging=me.mLogging;

if(logging!

=null){

logging.println(">>>>>Dispatchingto"+msg.target+""+

msg.callback+":

"+msg.what);

}

//消息派发:

把消息派发给msg的target属性,然后用dispatchMessage方法去处理

//Msg的target其实就是handler对象,下面会继续分析

msg.target.dispatchMessage(msg);

if(logging!

=null){

logging.println("<<<<

}

finallongnewIdent=Binder.clearCallingIdentity();

if(ident!

=newIdent){

Log.wtf(TAG,"Threadidentitychangedfrom0x"

+Long.toHexString(ident)+"to0x"

+Long.toHexString(newIdent)+"whiledispatchingto"

+msg.target.getClass().getName()+""

+msg.callback+"what="+msg.what);

}

//释放消息占据的资源

msg.recycle();

}

}

总结Looper的作用:

1.实例化本身、与当前线程绑定、创建与之相应的MessageQueue:

prepare()方法

一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue

消息循环(消息取出、消息派发):

loop()方法

不断从MessageQueue中去取消息,派发给消息的target属性的Handler,然后调用相应Handler的dispatchMessage()方法进行消息处理。

第二部分:

Handler

主要负责:

1.在子线程发送消息给MessageQueue2.处理Looper派发过来的消息使用Handler之前,会初始化一个Handler实例

Handler是需要和线程绑定在一起的,在初始化Handler的时候一般通过指定Looper对象从而绑定相应线程,即给Handler指定Looper对象=绑定到了Looper对象所在的线程中,Handler的消息处理回调会在那个线程中执行。

一般有两种方法创建:

1.通过Loop.myLooper()得到当前线程的Looper对象/通过Loop.getMainLooper()可以获得当前进程的主线程的Looper对象。

2.不指定Looper对象,那么这个Handler绑定到了创建这个线程的线程上,消息处理回调也就在创建线程中执行.

首先看Handler的构造方法

publicHandler(){

this(null,false);

}

publicHandler(Callbackcallback,booleanasync){

if(FIND_POTENTIAL_LEAKS){

finalClass

extendsHandler>klass=getClass();

if((klass.isAnonymousClass()||klass.isMemberClass()||klass.isLocalClass())&&

(klass.getModifiers()&Modifier.STATIC)==0){

Log.w(TAG,"ThefollowingHandlerclassshouldbestaticorleaksmightoccur:

"+

klass.getCanonicalName());

}

}

//通过Looper.myLooper()获取了当前线程保存的Looper实例,如果线程没有Looper实例那么会抛出异常

//这说明在一个没有创建Looper的线程中是无法创建一个Handler对象的

//所以说我们在子线程中创建一个Handler时首先需要创建Looper,并且开启消息循环才能够使用这个Handler。

mLooper=Looper.myLooper();

if(mLooper==null){

thrownewRuntimeException(

"Can'tcreatehandlerinsidethreadthathasnotcalledLooper.prepare()");

}

//获取了这个Looper实例中保存的MessageQueue(消息队列)

//这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了

mQueue=mLooper.mQueue;

mCallback=callback;

mAsynchronous=async;

}

上述说明:

当Handler初始化时,可通过构造方法自动关联Looper和相应的MessageQueue

1.Handler向MessageQueue发送消息:

对于Handler的发送方式可以分为post和send两种方式。

send的发送方法:

sendMessage()

publicfinalbooleansendMessage(Messagemsg)

{

returnsendMessageDelayed(msg,0);

}

//我们往下扒

publicfinalbooleansendEmptyMessageDelayed(intwhat,longdelayMillis){

Messagemsg=Message.obtain();

msg.what=what;

returnsendMessageDelayed(msg,delayMillis);

}

publicfinalbooleansendMessageDelayed(Messagemsg,longdelayMillis)

{

if(delayMillis<0){

delayMillis=0;

}

returnsendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);

}

publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){

//直接获取MessageQueue

MessageQueuequeue=mQueue;

if(queue==null){

RuntimeExceptione=newRuntimeException(

this+"sendMessageAtTime()calledwithnomQueue");

Log.w("Looper",e.getMessage(),e);

returnfalse;

}

//调用了enqueueMessage方法

returnenqueueMessage(queue,msg,uptimeMillis);

}

//调用sendMessage方法其实最后是调用了enqueueMessage方法

privatebooleanenqueueMessage(MessageQueuequeue,Messagemsg,longuptimeMillis){

//为msg.target赋值为this,也就是把当前的handler作为msg的target属性

//如果大家还记得Looper的loop()方法会取出每个msg然后执行msg.target.dispatchMessage(msg)去处理消息,其实就是派发给相应的Handler

msg.target=this;

if(mAsynchronous){

msg.setAsynchronous(true);

}

//最终调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。

returnqueue.enqueueMessage(msg,uptimeMillis);

}

Post的发送方法:

sendMessage()

showhandler.post(newRunnable(){

@Override

publicvoidrun(){

Stringline="\n";

StringBuffertext=newStringBuffer(show.getText());

text.append(line).append("angelababy:

Yes,Ido");

show.setText(text);

}

相比send方法,post方法最大的不同在于,更新UI操作可直接在重写的run方法定义。

其实Runnable并没有创建什么线程,而是发送了一条消息,下面看源码:

publicfinalbooleanpost(Runnabler)

{

returnsendMessageDelayed(getPostMessage(r),0);

}

privatestaticMessagegetPostMessage(Runnabler){

//创建了一个Message对象

//创建Message对象可以new,也可以使用Message.obtain()方法;

//但是更建议使用obtain方法,因为Message内部维护了一个Message池用于Message的复用,避免使用new重新分配内存。

Messagem=Message.obtain();

//将我们创建的Runable对象作为callback属性,赋值给了此message.

m.callback=r;

//创建了一个Message对象

returnm;

}

publicfinalbooleansendMessageDelayed(Messagemsg,longdelayMillis)

{

if(delayMillis<0){

delayMillis=0;

}

returnsendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);

}

publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){

MessageQueuequeue=mQueue;

if(queue==null){

RuntimeExceptione=newRuntimeException(

this+"sendMessageAtTime()calledwithnomQueue");

Log.w("Looper",e.getMessage(),e);

returnfalse;

}

returnenqueueMessage(queue,msg,uptimeMillis);

}

从上面的源码发现了吧?

和send中的handler.sendMessage是一样的。

调用了sendMessageAtTime,然后调用了enqueueMessage方法,给msg.target赋值为handler,最终Handler将消息加入MessagQueue.

但是细心的你会发现,在使用Post方法时会将我们创建的Runable对象作为callback属性赋值给了此message

那么msg的callback和target都有值,那么会执行哪个呢?

我们已知回调发送消息的方法是:

dispatchMessage()

publicvoiddispatchMessage(Messagemsg){

//一开始就会进行判断

//如果msg.callback属性不为null,则执行callback回调,也就是我们的Runnable对象

if(msg.callback!

=null){

handleCallback(msg);

}else{

if(mCallback!

=null){

if(mCallback.handleMessage(msg)){

return;

}

}

handleMessage(msg);

}

}

####2.处理Looper派发过来的消息:

dispathMessage()方法

publicvoiddispatchMessage(Messagemsg){

if(msg.callback!

=null){

handleCallback(msg);

}else{

if(mCallback!

=null){

if(mCallback.handleMessage(msg)){

return;

}

}

handleMessage(msg);

}

}

publicvoidhandleMessage(Messagemsg){

}

可以看到dispathMessage()方法里调用了handleMessage()方法,但handleMessage()是一个空方法

因为Handler发送消息过来是希望进行一定的处理,至于怎么处理消息是该Handler最终控制的,所以我们在创建handler时需要通过复写handleMessage()方法从而实现我们需要的消息处理方式,然后根据msg.what标识进行消息处理。

这就是为什么我们在主线程中实例化Handler的时候需要重写handleMessage()

特别注意

在一个Android应用启动的时候,会创建一个主线程,即ActivityThread(也叫UI线程),在ActivityThread中有一个静态的main方法:

应用程序的入口点

//一个进程会默认生成一个主线程

publicstaticvoidmain(String[]args){

......

//主线程生成时自动通过prepareMainLooper方法为主线程创建一个Looper

//prepare()方法是用于在子线程中创建一个Looper对象,在子线程中是可以退出消息循环的:

调用消息队列的quit方法

//Looper生成时会自动生成与之配套的消息队列

Looper.prepareMainLooper();

ActivityThreadthread=newAct

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1