对android消息机制的浅解:

来源:互联网 发布:阿里云代理收入 编辑:程序博客网 时间:2024/06/05 22:53
是线程间通信的方式
A: 很多情况下,我们都会进行耗时的操作(像网络访问(当然,网络访问本身也不能放在主线
程中执行),大文件存取,多量大图片处理等),那么为了避免ANR,我们不得不在子线程中操作.
遗憾的是,在很多这样的情况中,我们经常会遇到操作完成之后要更新UI的境况,那么问题就来
了,android不支持在子线程更新UI(当界面可见时,系统会启动审查机制,如果UI的更新是由UI
线程之外的线程来执行的话,就会抛出异常,谷歌歌歌歌的设计),这也涉及到了线程间通信.
这时候,就需要我们的Handler机制了.


B: Handler机制的原理:既然我们不能在子线程中更新UI,那么我们就要想办法把更新UI的操
做放到主线程中去.UI线程中维护着一个消息队列(MessageQueue),和一个轮询器(Looper),我们
把新创建的消息,通过Handler对象(在UI线程中创建)发送到消息队列中,轮询器会不停的访问消
息队列,发现新的消息之后,会立刻把消息发送给我们创建的Handler,handler中的handleMessage()
方法接收到消息,我们可以通过重写这个方法来执行想要的操作(更新UI).
整个过程大概就是这个样子.总的来说,就是我们从子线程中发送一个消息给主线程中的中转站,
再由中转站把消息发回给我们在主线程安排好的接收者,来执行消息里面的动作.是不是有点绕圈?
说白了从头到尾就是我们自己给自己发消息,,,,,,好处就是避免了ANR.


C: 具体步骤:
第一步,我们在子线程中创建一个Message,,用来暂存需要更新到UI的数据
或者Runnable对象,是执行UI更新等的操作.
第二步,在我们的UI线程(main)中创建一个Handler对象,用来发送和接收消息.
第三步,在子线程需要的地方用handler的sendMessage()或者post()方法把消息发送出去.
*第四步,发送出来的消息被压入消息队列的最后(其实位置可以手动调整).
*第五步,等待被执行.轮询器looper的执行时阻塞式的,只能执行完成一个,再执行另一个.
*第六步,消息在轮询器中被发送回handler,回收.
第七步,handler对象的handleMessage()方法接收到消息,执行我们自己在此方法中的代码.
注:*是系统步骤
D: API了解:
一,Message类:
1,创建消息:
①可以直接new出来,但是不推荐.
②执行静态方法,Message.obtain(),从消息池中获取一个引用.
③使用Handler对象的obtainMessage()方法,从消息池中获取一个引用.
④copyFrom(Message msg),从另一个消息中拷贝一个.
同时也可以在参数中制定目标handler,复制一个消息,保留原消息中的内容或者目标,等等.
每一个消息都需要一个目标handler,用以发送接收处理消息.
2,消息的参数设置:
①设置类型:Message.what
②设置数据:Message.obj
③设置额外参数:Message.arg1;Message.arg2
④设置目标:setTarget()设置要发送给谁(Handler)
等.


3,消息的发送:
①msg.sendToTarget()方法,前提是已经设置了目标Handler.
②handler.sendMessage()方法,这个方法也有很多重载或者类似的方法.
比如sendEmptyMessage(),sendMessageDelayed()等等.


4,消息的接收:
消息的接收过程我们是无法参与的,但是最后在handler中的handleMessage()
方法中可以获取消息中携带的信息,进而执行对应的操作.
如通过msg.what可以区分不同的消息,通过msg.obj可以获取它携带的数据等等


5,消息的回收利用:
执行msg.recycle()方法.把消息放进消息池,我们也再不能操作它了.
消息池中存放着Message对象的引用,使用1中的②③④就可以获取到.
相对于新建一个,提高了效率,节省了空间.
6,其他:
①通过getWhen()方法知道消息的交货时间
②通过getTarget()方法知道消息的目标Handler
③通过getData()方法获取携带的数据.
等等.
二,Runnable接口:
Runnable对象也是可以作为Handler发送的对象的,
通过handler的post()方法以及它的重载方法或者类似方法如handler.postAtTime()等方法
就可以把run()方法中的操作发送到主线程中来执行.
其实activity中的runOnUIThread()方法和View.post()方法都是使用了handler.post()方法.
因为Activity和View内部都维护着Handler对象.


三,Handler类:
1,创建对象:
直接new,有多参构造,可以添加回调,Looper等
2,获取Message:
底层是调用Message的obtain()方法,从消息池中获取.
obtainMessage()
obtainMessage(int what)
obtainMessage(int what, Object obj)
等等重载的方法
3,Runnable的发送:
post()方法以及其重载方法
也可以把Runnable对象放在消息队列的最前面postAtFrontOfQueue(Runnable r)
4,发送消息Message:
sendMessage()及其重载方法
也可以把消息放在消息队列的最前面sendMessageAtFrontOfQueue(Message msg)
5,移除一个消息
removeMessages(int what) 
6,判断消息队列中是否有一个Message.what是给定值得消息
hasMessages(int what)
重载:hasMessages(int what, Object object)
7,分发消息
dispatchMessage(Message msg)
8,消息处理
handleMessage(Message msg)
由子类实现,重写此方法,执行自己的操作
9,获取当前的轮询器
getLooper();


四,MessageQueue类:
holding the list of messages to be dispatched by a Looper
消息队列,由轮询器Looper分发内部的消息.


五,Looper类:
1,loop()方法:
①在loop()方法中,可以看出,它是阻塞式的,只有当一个消息被分发,回收之后,
才会操作队列中的下一个消息
Message msg = queue.next(); // might block
②消息的分发也是在这个方法中执行的,但是却是由handler来执行的,
msg.target.dispatchMessage(msg);
msg.target就是消息的handler,然后调用了handler的dispatchMessage(msg);方法
③消息的分发完成之后,就会执行msg.recycle();方法.回收消息,等待复用.
2,其他方法自行研究吧


E: 能够在子线程中更新UI的控件:ProgressBar和SurfaceView
F: 在子线程中更新UI的方法:
1,在子线程中创建一个Message或者Runnable对象,使用Handler发送,重写handleMessage()方法.
2,使用runOnUIThread()方法,参数是一个Runnable对象,重写run()方法,里面是更新UI的操作.
3,View.post()方法,参数也是一个Runnable对象,重写run()方法,里面是更新UI的操作.

其实如果翻看他们的源码,不难发现,他们的底层实现是一样的,都是Handler机制.

有不对的地方,欢迎指正.

1 0
原创粉丝点击