Android消息机制学习
2011-10-17 22:23
323 查看
百度面试,被问到了这个问题。其实是我挖的“坑”,但是还没有弄得很透彻。不知道面试官怎么想的了。
今天回来,好好整理了下。应该差不多了,恩,以后的“坑”。
第一篇文献:
深入剖析Android消息机制
http://www.cnblogs.com/coolszy/archive/2011/04/25/2026662.html
四个概念:
1.Message
消息对象,顾名思义就是记录消息信息的类。这个类有几个比较重要的字段:
a.arg1和arg2:我们可以使用两个字段用来存放我们需要传递的整型值,在Service中,我们可以用来存放Service的ID。
b.obj:该字段是Object类型,我们可以让该字段传递某个多项到消息的接受者中。
c.what:这个字段可以说是消息的标志,在消息处理中,我们可以根据这个字段的不同的值进行不同的处理,类似于我们在处理Button事件时,通过switch(v.getId())判断是点击了哪个按钮。
在使用Message时,我们可以通过new Message()创建一个Message实例,但是Android更推荐我们通过Message.obtain()或者Handler.obtainMessage()获取Message对象。这并不一定是直接创建一个新的实例,而是先从消息池中看有没有可用的Message实例,存在则直接取出并返回这个实例。反之如果消息池中没有可用的Message实例,则根据给定的参数new一个新Message对象。通过分析源码可得知,Android系统默认情况下在消息池中实例化10个Message对象。
2.MessageQueue
倘若我们的线程中存在Looper对象,则我们可以通过Looper.myLooper()获取,此外我们还可以通过Looper.getMainLooper()获取当前应用系统中主线程的Looper对象。在这个地方有一点需要注意,假如Looper对象位于应用程序主线程中,则Looper.myLooper()和Looper.getMainLooper()获取的是同一个对象。
3.looper
looper作用就是就是管理messagequeue。
4.Handler
消息的处理者。通过Handler对象我们可以封装Message对象,然后通过sendMessage(msg)把Message对象添加到MessageQueue中;当MessageQueue循环到该Message时,就会调用该Message对象对应的handler对象的handleMessage()方法对其进行处理。由于是在handleMessage()方法中处理消息,因此我们应该编写一个类继承自Handler,然后在handleMessage()处理我们需要的操作。
消息就是消息,处理还是在自己线程里面处理的。
消息就是可以开始了,可以结束了的信号灯。
线程之间相互发消息,就可以合作了。
第二代码:
我的项目里面,进度条的实现:
这里,handler不断把runnable对象post到UI线程里面,UI线程再来处理。其实,这里并没有新起一个线程。
真正的多线程
1.UI线程肯定是有的,凡是涉及到UI操作的动作,必须放在UI主线程里面去实现。因为UI线程不是安全的。
2.耗时操作不能放在UI线程里面去,因为耗时操作在UI线程中处理,会使得程序的体验性非常差劲。(你试着想象一下,你按下一个button按钮,程序就死在那里3秒钟,什么都不能做。)所以,耗时操作新起一个线程,这时候,android系统来使用多线程进行处理。
3.线程之间如何交互?这里就要使用android的消息机制了。线程A给线程B发消息,发来的消息放在线程B的messagequeue里面。
具体地可以参见下面这个问题:
http://zhidao.baidu.com/question/275665210.html?pt=monline_ik
耗时操作在新起的一个线程中去做;(此时就是多线程,线程的调度有系统来完成。)
更新UI的操作在主线程中完成,但不是耗时操作(post runnble对象到主UI线程中,等到UI线程来做;)
http://zhidao.baidu.com/question/275665210.html?pt=monline_ik
看下面这个问题就明白了:
android handler调用post方法还是阻塞
2011-6-4 16:19
提问者:贩卖孤独 | 浏览次数:284次
sureButton.setOnClickListener(new Button.OnClickListener(){
public void onClick(View view){
myHandler.post(new Runnable() {
public void run() {
getWeatherInfo();//耗时操作
analyzing();//耗时操作
setWeather();//更新UI
}
});
}
});
为什么这样写还是会阻塞掉。点了sureButton按钮之后,按钮会一直处于按下状态,
直到三个操作完成,才弹出来。。。
定义一个线程。
class MyThread extends Thread{
Handler mHandler;
Boolean boo;
public MyThread(Handler handler){
mHandler = handler;
}
public void setBoo(boolean b) {boo = b; }
publid void run(){
if(boo){
getWeatherInfo();//耗时操作
analyzing();//耗时操作
mHandler.post(new Runnable() {
public void run() {
setWeather();//更新UI
}
);//更新UI
boo = true;
}
}
}
在处理单击事件时:
sureButton.setOnClickListener(new Button.OnClickListener(){
public void onClick(View view){
setBoo(true);
myThread.start();
}
});
注意这里,setWeather是更新界面的操作,所以被放进了runnbale对象,然后被handler.post
到了UI线程,注意,由UI线程处理。
耗时的getWeatherInfo()和analyzing()放在了另外一个线程中处理。这样,就不会出现ANR
(application not responsible)的问题了。
UI线程是不安全的,意味着如果要更新UI,必须在UI线程中操作。
其实进度条的刷新显示并没有多线程,而是不断地延时1s将runnable对象通过handler调入主
线程的messagequeue中。按照下面的说法就是:
http://yzw2007.iteye.com/blog/724641
这是android提供的一种机制,handler对象将通过post方法,将里面的Runnable对象放到UI执行队列中,UI消费这个队列,调用Runnable的run方法。这里并不生成新的线程。项目中其实用到就是每间1s中将runnable对象扔进主线程里面,让主线程去做这件事情(更新界面:setProgress())。至于消息机制,还暂时没有用到:
发送消息实际上就是相当于发一个通知一样,只是通知作用。只有收到相应的通知,才会做自己的事情。
5.最后一个例子:
模拟下载文件(一个耗时操作),下载完毕后,通知主线程。
http://android.yaohuiji.com/archives/770
今天回来,好好整理了下。应该差不多了,恩,以后的“坑”。
第一篇文献:
深入剖析Android消息机制
http://www.cnblogs.com/coolszy/archive/2011/04/25/2026662.html
四个概念:
1.Message
消息对象,顾名思义就是记录消息信息的类。这个类有几个比较重要的字段:
a.arg1和arg2:我们可以使用两个字段用来存放我们需要传递的整型值,在Service中,我们可以用来存放Service的ID。
b.obj:该字段是Object类型,我们可以让该字段传递某个多项到消息的接受者中。
c.what:这个字段可以说是消息的标志,在消息处理中,我们可以根据这个字段的不同的值进行不同的处理,类似于我们在处理Button事件时,通过switch(v.getId())判断是点击了哪个按钮。
在使用Message时,我们可以通过new Message()创建一个Message实例,但是Android更推荐我们通过Message.obtain()或者Handler.obtainMessage()获取Message对象。这并不一定是直接创建一个新的实例,而是先从消息池中看有没有可用的Message实例,存在则直接取出并返回这个实例。反之如果消息池中没有可用的Message实例,则根据给定的参数new一个新Message对象。通过分析源码可得知,Android系统默认情况下在消息池中实例化10个Message对象。
2.MessageQueue
倘若我们的线程中存在Looper对象,则我们可以通过Looper.myLooper()获取,此外我们还可以通过Looper.getMainLooper()获取当前应用系统中主线程的Looper对象。在这个地方有一点需要注意,假如Looper对象位于应用程序主线程中,则Looper.myLooper()和Looper.getMainLooper()获取的是同一个对象。
3.looper
looper作用就是就是管理messagequeue。
4.Handler
消息的处理者。通过Handler对象我们可以封装Message对象,然后通过sendMessage(msg)把Message对象添加到MessageQueue中;当MessageQueue循环到该Message时,就会调用该Message对象对应的handler对象的handleMessage()方法对其进行处理。由于是在handleMessage()方法中处理消息,因此我们应该编写一个类继承自Handler,然后在handleMessage()处理我们需要的操作。
消息就是消息,处理还是在自己线程里面处理的。
消息就是可以开始了,可以结束了的信号灯。
线程之间相互发消息,就可以合作了。
第二代码:
我的项目里面,进度条的实现:
Handler handler=new Handler(); private OnClickListener playlis=new OnClickListener(){ @Override public void onClick(View v) { // TODO Auto-generated method stub handler.post(start); //调用handler播放 } }; Runnable start=new Runnable(){ @Override public void run() { // TODO Auto-generated method stub // mp.reset(); // mp =MediaPlayer.create(main.this,Uri.parse ("/sdcard/test.mp3")); mp.start(); handler.post(updatesb); //用一个handler更新SeekBar } }; Runnable updatesb =new Runnable(){ @Override public void run() { // TODO Auto-generated method stub sb.setProgress(mp.getCurrentPosition()); handler.postDelayed(updatesb, 1000); //每秒钟更新一次 } };
这里,handler不断把runnable对象post到UI线程里面,UI线程再来处理。其实,这里并没有新起一个线程。
真正的多线程
1.UI线程肯定是有的,凡是涉及到UI操作的动作,必须放在UI主线程里面去实现。因为UI线程不是安全的。
2.耗时操作不能放在UI线程里面去,因为耗时操作在UI线程中处理,会使得程序的体验性非常差劲。(你试着想象一下,你按下一个button按钮,程序就死在那里3秒钟,什么都不能做。)所以,耗时操作新起一个线程,这时候,android系统来使用多线程进行处理。
3.线程之间如何交互?这里就要使用android的消息机制了。线程A给线程B发消息,发来的消息放在线程B的messagequeue里面。
具体地可以参见下面这个问题:
http://zhidao.baidu.com/question/275665210.html?pt=monline_ik
耗时操作在新起的一个线程中去做;(此时就是多线程,线程的调度有系统来完成。)
更新UI的操作在主线程中完成,但不是耗时操作(post runnble对象到主UI线程中,等到UI线程来做;)
http://zhidao.baidu.com/question/275665210.html?pt=monline_ik
看下面这个问题就明白了:
android handler调用post方法还是阻塞
2011-6-4 16:19
提问者:贩卖孤独 | 浏览次数:284次
sureButton.setOnClickListener(new Button.OnClickListener(){
public void onClick(View view){
myHandler.post(new Runnable() {
public void run() {
getWeatherInfo();//耗时操作
analyzing();//耗时操作
setWeather();//更新UI
}
});
}
});
为什么这样写还是会阻塞掉。点了sureButton按钮之后,按钮会一直处于按下状态,
直到三个操作完成,才弹出来。。。
定义一个线程。
class MyThread extends Thread{
Handler mHandler;
Boolean boo;
public MyThread(Handler handler){
mHandler = handler;
}
public void setBoo(boolean b) {boo = b; }
publid void run(){
if(boo){
getWeatherInfo();//耗时操作
analyzing();//耗时操作
mHandler.post(new Runnable() {
public void run() {
setWeather();//更新UI
}
);//更新UI
boo = true;
}
}
}
在处理单击事件时:
sureButton.setOnClickListener(new Button.OnClickListener(){
public void onClick(View view){
setBoo(true);
myThread.start();
}
});
注意这里,setWeather是更新界面的操作,所以被放进了runnbale对象,然后被handler.post
到了UI线程,注意,由UI线程处理。
耗时的getWeatherInfo()和analyzing()放在了另外一个线程中处理。这样,就不会出现ANR
(application not responsible)的问题了。
UI线程是不安全的,意味着如果要更新UI,必须在UI线程中操作。
其实进度条的刷新显示并没有多线程,而是不断地延时1s将runnable对象通过handler调入主
线程的messagequeue中。按照下面的说法就是:
http://yzw2007.iteye.com/blog/724641
这是android提供的一种机制,handler对象将通过post方法,将里面的Runnable对象放到UI执行队列中,UI消费这个队列,调用Runnable的run方法。这里并不生成新的线程。项目中其实用到就是每间1s中将runnable对象扔进主线程里面,让主线程去做这件事情(更新界面:setProgress())。至于消息机制,还暂时没有用到:
发送消息实际上就是相当于发一个通知一样,只是通知作用。只有收到相应的通知,才会做自己的事情。
5.最后一个例子:
模拟下载文件(一个耗时操作),下载完毕后,通知主线程。
http://android.yaohuiji.com/archives/770
相关文章推荐
- 学习Android Handler消息传递机制
- Android学习札记26:深入理解Android中的消息处理机制——Thread、Looper、MessageQueue和Handler(1)
- android异步消息处理机制 handler MessageQueue Looper 类 学习
- Android(java)学习笔记203:网页源码查看器(Handler消息机制)
- Android应用开发学习笔记之多线程与Handler消息处理机制
- android消息处理机制学习(一)-Handler,Message,MessageQueue,Looper简介
- Android异步消息机制和AsyncTask接口的使用 [学习笔记]
- android学习14#--Handler消息传递机制实例应用
- Android学习历程10-Handler消息传递机制
- 安卓学习笔记之Android消息机制
- Android的消息机制学习(一)Looper,Handler,MessageQueue
- Android异步消息处理机制学习笔记
- android的消息机制之学习笔记
- android学习13#--Handler消息传递机制
- android开发学习(四)——anr产生的原理&如何避免,android消息机制入门, 网络图片查看器
- android学习----消息机制
- Android学习心得(24) --- Android Handler消息机制源码分析
- android学习之——Handler消息传递机制
- android消息处理机制学习(三)-Handler,Message,MessageQueue,Looper源码分析
- Android学习之消息机制相关类介绍