ImageVerifierCode 换一换
格式:DOCX , 页数:21 ,大小:98.13KB ,
资源ID:6858462      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6858462.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Android开发Handler异步通信机制全面解析包含LooperMessage Queue.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

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

1、Android开发Handler异步通信机制全面解析包含LooperMessage QueueAndroid开发:Handler异步通信机制全面解析(包含Looper、Message Queue)定义Android提供的一套消息传递机制作用用于实现子线程对UI线程的更新,实现异步消息的处理: - 在新启动的线程中发送消息 - 在主线程中获取并处理信息为什么要用Handler在安卓开发中: - 为了保证Android的UI操作是线程安全的,Android规定了只允许UI线程修改Activity里的UI组件; - 但在实际开发中,必然会用到多个线程并发操作UI组件,这又将导致UI操作的线程不安全所

2、以问题在于:如何同时满足: - 保证线程安全 - 使多个线程并发操作UI组件Handler消息传递机制就是解决这个问题的。相关概念主线程(UI线程) - 定义:当程序第一次启动时,Android会同时启动一条主线程(Main Thread) - 作用:主线程主要负责处理与UI相关的事件,所以主线程又叫UI线程子线程则负责一些比较耗时的操作(联网、取数据、SD卡数据加载等操作),而主线程和子线程之间的通信,就是要靠Handler了。Message - 定义:消息,理解为线程间通讯的数据单元(Handler接受和处理的消息对象。)例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的

3、Message给UI线程Message Queue - 定义:消息队列 - 作用:用来存放通过Handler发过来的消息,按照先进先出执行Handler - 定义:Handler是Message的主要处理者 - 作用:负责将Message添加到消息队列&处理Looper分派过来的MessageLooper - 定义:循环器,扮演Message Queue和Handler之间桥梁的角色作用:主要负责消息循环:循环取出Message Queue的Message;消息派发:将取出的Message交付给相应的Handler 每个线程中只能拥有一个Looper,但是一个Looper可以和多个线程的Han

4、dler绑定起来,也就是说很多个线程可以往一个Looper所持有的MessageQueue中发送消息。这就给我们提供了线程之间通信的可能。 Handler在创建的时候可以显示指定Looper,这样在Handler在调用sendMessage()投递消息的时候会将消息添加到指定的Looper里面的MessageQueue。如果不指定Looper,Handler默认绑定的是创建它的线程的Looper。Handler异步通信机制工作流程图!Handler异步通信传递机制流程图(Handler、Looper、MessageQueue关系类图!( *Handler* - 提供sendMessage方法,

5、将消息放置到队列中 - 提供handleMessage方法,定义个各种消息的处理方式; *Looper* - Looper.prepare():实例化Looper对象;为当前线程生成一个消息队列; - Looper.loop() :循环从消息队列中获取消息,交给Handler处理;此时线程处于无限循环中,不停的从MessageQueue中获取Message 消息 ;如果没有消息就阻塞 *MessageQueue* - 提供enqueueMessage 方法,将消息根据时间放置到队列中; - 提供next方法,从队列中获取消息,没有消息的时候阻塞; *Handler工作流程解释* 异步通信传递机

6、制步骤主要包括异步通信的准备、消息发送、消息循环和消息处理异步通信的准备 包括Looper对象的创建&实例化、MessageQueue队列的创建和Handler的实例化消息发送 Handler将消息发送到消息队列中消息循环 Looper执行Looper.loop()进入消息循环,在这个循环过程中,不断从该Message Queue取出消息,并将取出的消息派发给创建该消息的Handler消息处理 调用该Handler的dispatchMessage(msg)方法,即回调handleMessage(msg)处理消息好像很复杂?那就先看下这个简图了解下: !(工作流程详细讲解由上面可以得知,整个异步

7、消息传递机制主要包括Handler、Looper和MessageQueue,接下来通过相应源码来解析这三部分第一部分:LooperLooper主要负责: 1. 自身的创建&创建Message Queue 2. 消息循环(消息取出、派发) 对应职责我们来看下相应的源码: 1. 自身的创建&创建Message Queue:prepare()方法public static final void prepare() /判断sThreadLocal是否为null,否则抛出异常/即Looper.prepare()方法不能被调用两次/也就是说,一个线程中只能对应一个Looper实例 if (sThreadL

8、ocal.get() != null) throw new RuntimeException(Only one Looper may be created per thread); /sThreadLocal是一个ThreadLocal对象,用于在一个线程中存储变量/实例化Looper对象并存放在ThreadLocal/这说明Looper是存放在Thread线程里的 sThreadLocal.set(new Looper(true);/再来看下Looper的构造方法private Looper(boolean quitAllowed) /创建了一个MessageQueue(消息队列)/这说明,

9、当创建一个Looper实例时,会自动创建一个与之配对的MessageQueue(消息队列) mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread();*2. 消息循环:loop()方法*public static void loop() /myLooper()方法作用是返回sThreadLocal存储的Looper实例,如果me为null,loop()则抛出异常/也就是说loop方法的执行必须在prepare方法之后运行/也就是说,消息循环必须要先在线程当中创建Looper实例 f

10、inal Looper me = myLooper(); if (me = null) throw new RuntimeException(No Looper; Looper.prepare() wasnt called on this thread.); /获取looper实例中的mQueue(消息队列) final MessageQueue queue = me.mQueue; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();/进入消息循环 for (;) /next()方法用

11、于取出消息队列里的消息/如果取出的消息为空,则线程阻塞 Message msg = queue.next(); / might block if (msg = null) return; Printer logging = me.mLogging; if (logging != null) logging.println( Dispatching to + msg.target + + msg.callback + : + msg.what); /消息派发:把消息派发给msg的target属性,然后用dispatchMessage方法去处理/Msg的target其实就是handler对象,下面

12、会继续分析 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(newId

13、ent) + while dispatching to + msg.target.getClass().getName() + + msg.callback + what= + msg.what); /释放消息占据的资源 msg.recycle(); 总结Looper的作用: 1. 实例化本身、与当前线程绑定、创建与之相应的MessageQueue:prepare()方法一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue消息循环(消息取出、消息派发):loop()方法 不断从MessageQueue中去取消息,派发给消息的target属性的Handl

14、er,然后调用相应Handler的dispatchMessage()方法进行消息处理。第二部分:Handler主要负责: 1. 在子线程发送消息给MessageQueue 2. 处理Looper派发过来的消息 使用Handler之前,会初始化一个Handler实例Handler是需要和线程绑定在一起的,在初始化Handler的时候一般通过指定Looper对象从而绑定相应线程,即给Handler指定Looper对象=绑定到了Looper对象所在的线程中,Handler的消息处理回调会在那个线程中执行。一般有两种方法创建: 1. 通过Loop.myLooper()得到当前线程的Looper对象/通

15、过Loop.getMainLooper()可以获得当前进程的主线程的Looper对象。 2. 不指定Looper对象,那么这个Handler绑定到了创建这个线程的线程上,消息处理回调也就在创建线程中执行.首先看Handler的构造方法public Handler() this(null, false);public Handler(Callback callback, boolean async) if (FIND_POTENTIAL_LEAKS) final Class klass = getClass(); if (klass.isAnonymousClass() | klass.isMe

16、mberClass() | klass.isLocalClass() & (klass.getModifiers() & Modifier.STATIC) = 0) Log.w(TAG, The following Handler class should be static or leaks might occur: + klass.getCanonicalName(); /通过Looper.myLooper()获取了当前线程保存的Looper实例,如果线程没有Looper实例那么会抛出异常/这说明在一个没有创建Looper的线程中是无法创建一个Handler对象的/所以说我们在子线程中创建

17、一个Handler时首先需要创建Looper,并且开启消息循环才能够使用这个Handler。 mLooper = Looper.myLooper(); if (mLooper = null) throw new RuntimeException( Cant create handler inside thread that has not called Looper.prepare(); /获取了这个Looper实例中保存的MessageQueue(消息队列)/这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了 mQueue = mLooper.mQueu

18、e; mCallback = callback; mAsynchronous = async; 上述说明:当Handler初始化时,可通过构造方法自动关联Looper和相应的MessageQueue1. Handler向MessageQueue发送消息:对于Handler的发送方式可以分为post和send两种方式。send的发送方法:sendMessage() public final boolean sendMessage(Message msg) return sendMessageDelayed(msg, 0); /我们往下扒 public final boolean sendEmpt

19、yMessageDelayed(int what, long delayMillis) Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); public final boolean sendMessageDelayed(Message msg, long delayMillis) if (delayMillis 0) delayMillis = 0; return sendMessageAtTime(msg, SystemClock.uptimeMillis(

20、) + delayMillis); public boolean sendMessageAtTime(Message msg, long uptimeMillis) /直接获取MessageQueue MessageQueue queue = mQueue; if (queue = null) RuntimeException e = new RuntimeException( this + sendMessageAtTime() called with no mQueue); Log.w(Looper, e.getMessage(), e); return false; /调用了enqueu

21、eMessage方法 return enqueueMessage(queue, msg, uptimeMillis); /调用sendMessage方法其实最后是调用了enqueueMessage方法 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) /为msg.target赋值为this,也就是把当前的handler作为msg的target属性/如果大家还记得Looper的loop()方法会取出每个msg然后执行msg.target.dispatchMessage(msg)去处

22、理消息,其实就是派发给相应的Handler msg.target = this; if (mAsynchronous) msg.setAsynchronous(true); /最终调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。 return queue.enqueueMessage(msg, uptimeMillis); Post的发送方法:sendMessage() showhandler.post(new Runnable() Override public void run() String line = n; Strin

23、gBuffer text = new StringBuffer(show.getText(); text.append(line).append(angelababy:Yes,I do); show.setText(text); 相比send方法,post方法最大的不同在于,更新UI操作可直接在重写的run方法定义。其实Runnable并没有创建什么线程,而是发送了一条消息,下面看源码: public final boolean post(Runnable r) return sendMessageDelayed(getPostMessage(r), 0); private static Me

24、ssage getPostMessage(Runnable r) /创建了一个Message对象/创建Message对象可以new,也可以使用Message.obtain()方法;/但是更建议使用obtain方法,因为Message内部维护了一个Message池用于Message的复用,避免使用new 重新分配内存。 Message m = Message.obtain();/将我们创建的Runable对象作为callback属性,赋值给了此message. m.callback = r;/创建了一个Message对象 return m; public final boolean sendMe

25、ssageDelayed(Message msg, long delayMillis) if (delayMillis 0) delayMillis = 0; return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); public boolean sendMessageAtTime(Message msg, long uptimeMillis) MessageQueue queue = mQueue; if (queue = null) RuntimeException e = new RuntimeExc

26、eption( this + sendMessageAtTime() called with no mQueue); Log.w(Looper, e.getMessage(), e); return false; return enqueueMessage(queue, msg, uptimeMillis); 从上面的源码发现了吧?和send中的handler.sendMessage是一样的。调用了sendMessageAtTime,然后调用了enqueueMessage方法,给msg.target赋值为handler,最终Handler将消息加入MessagQueue.但是细心的你会发现,在

27、使用Post方法时会将我们创建的Runable对象作为callback属性赋值给了此message 那么msg的callback和target都有值,那么会执行哪个呢? 我们已知回调发送消息的方法是:dispatchMessage() public void dispatchMessage(Message msg) /一开始就会进行判断/如果msg.callback属性不为null,则执行callback回调,也就是我们的Runnable对象 if (msg.callback != null) handleCallback(msg); else if (mCallback != null) i

28、f (mCallback.handleMessage(msg) return; handleMessage(msg); #2. 处理Looper派发过来的消息:dispathMessage()方法public void dispatchMessage(Message msg) if (msg.callback != null) handleCallback(msg); else if (mCallback != null) if (mCallback.handleMessage(msg) return; handleMessage(msg); public void handleMessage

29、(Message msg) 可以看到dispathMessage()方法里调用了 handleMessage()方法,但handleMessage()是一个空方法因为Handler发送消息过来是希望进行一定的处理,至于怎么处理消息是该Handler最终控制的,所以我们在创建handler时需要通过复写handleMessage()方法从而实现我们需要的消息处理方式,然后根据msg.what标识进行消息处理。这就是为什么我们在主线程中实例化Handler的时候需要重写handleMessage()特别注意在一个Android应用启动的时候,会创建一个主线程,即ActivityThread(也叫UI线程),在ActivityThread中有一个静态的main方法:应用程序的入口点/一个进程会默认生成一个主线程public static void main(String args) ./主线程生成时自动通过prepareMainLooper方法为主线程创建一个Looper/prepare()方法是用于在子线程中创建一个Looper对象,在子线程中是可以退出消息循环的:调用消息队列的quit方法/Looper生成时会自动生成与之配套的消息队列Looper.prepareMainLooper(); ActivityThread thread = new Act

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

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