Handler机制

一、Handler的定义:

   Handler主要用于接收子线程发送过来的数据, 并用此数据配合主线程进行UI的更新。
   当应用程序启动时,Android首先会开启一个主线程 (UI线程),主线程主要为管理界面中的UI控件,进行事件的分发,好比如,你要点击一个 Button控件,Android就会通过此Buttond的监听器分发事件到此Button上,以此来响应你的操作。如果此时是一个需要耗时长的操作,例如:联网读取数据,或者读取本地较大的一个文件的时候,就不能把这些操作放在主线程当中了,如果被放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,会收到Android系统的一个错误提示“强制关闭”。这个时候就需要把这些耗时的操作,放在一个子线程当中了,因为子线程可能会涉及到UI的更新,当新线程中有涉及到操作UI的操作时,就会对主线程产生危险,因此,Android提供了Handler作为主线程和子线程的纽带。也就是说,更新UI只能在主线程当中进行更新,在子线程中操作是危险的。

   由于Handler是运行在主线程当中(UI线程中),它与子线程主要是通过Message对象来传递数据,这个时候,Handler就承担着接收子线程传过来的(子线程用sedMessage()方法传递)Message对象(里面包含数据),把这些消息放入主线程队列中,配合主线程进行更新UI。

   注意:Handler 对象初始化后,就默认与对它初始化的进程的消息队列绑定,因此可以利用Handler所包含的消息队列,制定一些操作的顺序。

 

二、Handler的主要作用

1. 传递Message,用于接收子线程发送过来的数据并用此数据配合主线程更新UI

    在Android中,对于UI的操作通常需要放在主线程中进行操作。如果在子线程中有关于UI的操作,那么就需要把数据消息作为一个Message对象发送到消息队列中,然后,由Handler中的handlerMessge()方法处理传过来的数据信息,并操作UI。当然,Handler对象是在主线程中初始化的,它需要绑定在主线程的消息队列中。

    类sendMessage(Message msg)方法实现发送消息的操作。在初始化Handler对象时重写的handleMessage()方法是用来来接收Messgae并进行相关操作的。

2. 传递Runnable对象,用于通过Handler绑定的消息队列,安排不同操作的执行顺序。

    Handler对象在进行初始化的时候,会默认的自动绑定消息队列。利用类post方法,可以将Runnable对象发送到消息队列中,按照队列的机制按顺序执行不同的Runnable对象中的run方法。

三、Handler的一些特点
handler可以分发Message对象或Runnable对象到主线程中,每个Handler实例,都会被绑定到创建它的线程中(一般是位于主线程)。
      
Handler中分发消息的一些方法:
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)

以上post类方法允许你排列一个Runnable对象到主线程队列当中;
sendMessage类方法,允许你安排一个带数据的Message对象到队列中。

注意:

   默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback) 可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个 Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以 sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在 其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。

### Handler机制原理 Android中的Handler机制是用于线程间通信的重要工具,它允许开发者在不同的线程中发送和处理消息。每个Handler实例都与一个线程及其消息队列相关联。当创建一个新的Handler对象时,它会自动绑定到当前线程的消息队列上。这个机制对于UI更新特别有用,因为Android的UI工具包不是线程安全的,并且规定只能在主线程中修改UI组件。 在底层实现上,Handler依赖于几个关键类:`Looper`、`MessageQueue` 和 `ThreadLocal`。`Looper` 是用来循环取出消息并分发给相应的Handler进行处理的对象。每个线程可以拥有一个`Looper`实例,而`Looper`则维护着一个`MessageQueue`,即消息队列。`MessageQueue`负责存储由Handler发送的消息。为了确保每个线程都有自己的`Looper`,使用了`ThreadLocal`来保证数据隔离[^4]。 要在一个非主线程中使用Handler,你需要手动调用`Looper.prepare()`方法来初始化该线程的`Looper`,然后通过调用`Looper.loop()`开始循环处理消息。而在应用程序的主活动中,系统已经为我们在主线程做好了这些初始化操作,因此可以直接使用Handler[^3]。 ### 使用详解 创建一个Handler通常涉及以下几个步骤: 1. 在需要接收和处理消息的线程中获取或创建一个`Looper`。 2. 创建一个继承自`Handler`的子类,并重写其`handleMessage(Message msg)`方法以定义如何处理接收到的消息。 3. 通过新创建的Handler对象发送消息,这可以通过多种方式完成,如`sendMessage(Message msg)`或者`post(Runnable r)`等方法。 下面是一个简单的示例代码展示如何在子线程中使用Handler: ```java new Thread(new Runnable() { @Override public void run() { // 准备当前线程的Looper Looper.prepare(); // 创建Handler final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // 处理消息 switch (msg.what) { case 1: // 执行某些操作 break; default: super.handleMessage(msg); } } }; // 发送一条空消息 handler.sendEmptyMessage(1); // 开始循环处理消息 Looper.loop(); } }).start(); ``` 在这个例子中,我们首先启动了一个新的线程,在其中准备了一个`Looper`,接着创建了一个自定义的`Handler`。一旦消息被发送(这里是使用`sendEmptyMessage(1)`),`Looper`就会从`MessageQueue`中取出这条消息并通过`handleMessage`方法来处理它。 此外,如果想让主线程中的Handler向子线程发送消息,则需要持有那个子线程对应的Handler引用。这样就可以跨线程传递信息了。 ### 注意事项 - 当不再需要一个Looper时,应该调用`quit()`或`quitSafely()`方法来终止消息循环,避免内存泄漏。 - 不要在非UI线程中直接访问UI组件;应利用Handler将结果返回到UI线程后再做更新。 - 需要合理管理生命周期,特别是在Activity或Service中使用时,防止因未正确关闭导致的应用崩溃或ANR问题。 通过理解上述原理及实践技巧,开发者能够更有效地运用Handler机制解决实际开发中的并发问题和提高应用性能。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值