Android的消息机制(一)

本文详细介绍了Android中的Handler机制,包括其核心组件MessageQueue和Looper的工作原理,以及如何利用Handler实现线程间通信,特别是子线程与UI线程的交互。

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

Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行,很多人认为Handler的作用是更新UI ,这的确没错,但是更新UI仅仅是它的一个特殊使用场景。有时候我们需要在子线程中进行耗时的I/O操作,可能是读取文件或者访问网络……,当耗时操作完成以后可能在UI上做一些改变,由于Android开发规范的限制,我们并不能在子线程访问UI控件,否则会触发程序异常,这个时候通过Handler就可以将更新UI的操作切换到主线程中执行。因此,本质上来说,Handler并不是专门用于更新UI的,它只是被开发人员用来更新UI。
Handler的运行需要底层的MessageQueue(消息队列)和Looper(消息循环)的支撑,MessageQueue内部存储了一组消息,以队列的形式对外提供插入和删除的工作,消息队列的内部存储结构并不是真正的队列,是采用单链表的数据结构来存储消息列表。Looper在这里可以理解为消息循环。由于MessageQueue只是一个消息的存储单元,他不能去处理消息,而Looper会以无限循环的形式去查找是否有新消息,如果有就处理,否则就一直等待着。Looper还有一个特殊的概念,那就是ThreadLocal,它不是一个线程,它的作用是可以在每个线程中存储数据。Handler创建的时候会采用当前线程的Looper来构造循环系统,Handler内部就是使用ThreadLocal在不同的线程中互不干扰地存储并提供数据,通过ThreadLocal可以轻松获取到每个线程的Looper.
注意:线程默认没有Looper,如果需要使用Handler就必须为线程创建Looper,我们经常提到的主线程就是UI线程(ActivityThread),ActivityThread被创建时就会初始化Looper,这就是在主线程中默认使用Handler的原因。


曾经一道尴尬的面试题:(Handler与Looper的对应关系,一对一,还是多对一)
消息处理类Handler允许发送和处理Message或Runnable对象到其所在线程的MessageQueue中。Handler主要有一下两个作用:

1.将Message或Runnable应用post()或sandMessage()方法发送到MessageQueue中,在发送时可以指定延迟时间、发送时间以及要携带的Bundle数据。当MessageQueue循环到该Message时,调用相应的Handler对象的handlerMessage()方法对其进行处理。

2.在子线程中与主线程进行通信,也就是在工作线程中与UI线程进行通信。

*在一个线程中,只能有一个Looper和MessageQueue,但是可以有多个Handler,而且这些Handler可以共享一个Looper和MessageQueue。

Handler类提供的发送和处理消息的常用方法如下表:
[plain] view plain copy

void handleMessage(Message msg):处理消息的方法,该方法通常用于被重写。   
final boolean hasMessage(int what):检查消息队列是否包含what属性指定值的消息。   
final boolean hasMessage(int what,Object object):检查消息队列中是否包含what属性为指定且object属性为指定指定对象的消息。   
Message obtainMessage():获取消息。   
sendEmptyMessage(int what):发送空消息。   
final boolean sendEmptyMessageDelayed(int what,long delayMillis):指定多少毫秒之后发送空消息。   
final boolean sendMessage(Message msg):立即发送消息。   
final boolean sendMessageAtTime(Message msg,long uptimeMillis):定时发送消息。   
final boolean sendMessageDelayed(Message msg,long delayMillis):指定多少毫秒之后发送消息。  

二.消息类(Message)简介
消息类(Message)被存放在MessageQueue中,一个MessageQueue中可以包含多个Message对象,每个Message对象可以通过Message.obtain()或Handler.obtainMessage()方法获得。一个Message对象有如下5个属性:
[plain] view plain copy

arg1 int类型 用来存放整型数据  
arg2 int类型 用来存放整型数据  
what int类型 用来保存消息标示  
obj Object类型 是Object类型的任意对象  
replyTo Messager类型 用来指定此Message发送到何处的可选Message对象  

*使用Message类的属性可以携带int类型数据,如果要携带其他类型的数据,可以先将要携带的数据保存到Bundle中对象中,然后通过Message类的setData()方法将其添加到Message中。
如:


Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putInt("int", 1);
bundle.putBoolean("boolean", false);
bundle.putByte("byte", (Byte) null);
bundle.putChar("char",'a');
bundle.putCharSequence("Stirng","Hello World");
bundle.putFloat("float", 12.3f);
bundle.putString("String", "Hello World");
bundle.putDouble("double", 12.3);
msg.setData(bundle);

总之,Message类的使用方法比较简单,在使用时,需注意以下3点:
a.尽管Message有public的默认构造方法,但是通常情况下,需要使用Message.obtaion()或Handler.obtainMessage()方法来从消息池中获得空消息对象,以节省资源。

b.如果一个Message只需要携带简单的int型信息,应优先使用Message.arg1和Message.arg2属性来传递信息,这比用Bundle更节省内存。

c.尽可能使用Message.what来标识信息,以便用不同方式处理Massage。


 /** 
                     *  
                     * handler.post(Runnable); 
                     *  
                     *  
                     */ 
                    handler.post(new Runnable() { 

                        @Override 
                        public void run() { 
                            isChanging = true; 
                            bar.setProgress(count); 
                            count++; 

                        } 


                    }); 


                    /** 
                     *  
                     *  
                     * hanlder.postDelayer(Runnable,timeDelayed); 
                     *  
                     */ 
                    handler.postDelayed(new Runnable() { 

                        @Override 
                        public void run() { 
                            isChanging = true; 
                            bar.setProgress(count); 
                            count++; 

                        } 

                    },100); 
    /** 
     * 重点看一下handler是怎么发送msg的 
     *  
     * 1.可以发送空的Message 
     * 2.可以定时发送Message 
     * 3.Message可以携带的数据有   int what,int arg1,int arg2,Object obj, Bundle bundler(通过msg.setData(Bundle bundler)来添加到Message对象中) 
     *  
     * 4.Message通过Handler.obtain()方法实例化,可以进行有参、无参实例化,其中有参实例化是可以出传入 int what,int arg1,int arg2, Object obj 
     * @author VicentTung 
     * 
     */ 

                    /** 
                     * 1.发送空的Message 
                     */ 

                    handler.sendEmptyMessage(0); 

                    handler.sendEmptyMessageAtTime(0, System.currentTimeMillis()); 

                    handler.sendEmptyMessageDelayed(0, 100); 


                    /** 
                     *2. 发送非空Message(Message是new出来的) 
                     */ 
                    Message msg =new Message(); 
                    Bundle data_bundle = new Bundle(); 
                    data_bundle.putString("name", "小明"); 
                    data_bundle.putInt("age", 12); 
                    msg.arg1=1; 
                    msg.arg2=2; 
                    msg.what=3; 
                    msg.obj="success"; 
                    msg.setData(data_bundle); 
                    handler.sendMessageDelayed(msg, 100); 

                    /** 
                     * 3.发送非空Message(Message是handler.obtain()出来的) 
                     */ 


                    String obj="hahah"; 
                    int arg1=111; 
                    int arg2=222; 
                    Message msg_obtain =handler.obtainMessage(); 

                    /** 
                     *  各种各样的带参数的obtain()方法实例化出Message对象 
                     */ 
                    msg_obtain =handler.obtainMessage(what); 
                    msg_obtain = handler.obtainMessage(what, obj); 
                    msg_obtain = handler.obtainMessage(what, arg1, arg2); 
                    msg_obtain =handler.obtainMessage(what, arg1, arg2, obj); 


                    /** 
                     * 4.Message的移除 
                     */ 


                    if(handler.hasMessages(0)){ 

                        handler.removeMessages(0); 
                    } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值