Android消息机制学习

本文深入解析Android中的消息机制,包括Message、MessageQueue、Looper及Handler的概念与使用方式,并通过实例展示了如何利用Handler处理耗时任务及更新UI。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

百度面试,被问到了这个问题。其实是我挖的“坑”,但是还没有弄得很透彻。不知道面试官怎么想的了。

今天回来,好好整理了下。应该差不多了,恩,以后的“坑”。

第一篇文献:

深入剖析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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值