Handler消息传递机制

本文深入探讨了Android应用开发中如何利用Handler类实现线程间消息传递,解决了新线程动态修改UI组件的问题。通过Looper和MessageQueue的配合,详细介绍了Handler的使用方法及其实现原理。

Handler消息传递机制


出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,则可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的规定:只允许UI线程(主线程)修改Activity里的UI组件。

稍微想一想,如果新启动的线程需要动态修改界面组件怎么办呢。这时候就需要借助于Handler的消息机制来实现了。


Handler类简介

为了解决新线程动态修改界面组件的问题,所以引入了Handler类。所以Handler类主要作用有两个:

  • 在新启动的线程中发送消息
  • 在主线程中获取、处理消息

我们只需重写Handler类中处理消息的方法。当新启动的线程发送消息的时候,该消息就会放到与它相关的MessageQueue(不难想到,一个新线程只需要有一个MessageQueue)。Handler会不断从MessageQueue中获取并处理消息,这样就会让我们重写的方法被回调了。

Handler类包含如下的方法用于发送、处理消息:

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


Handler获取,处理消息

上面提到Handler是得到消息,然后处理消息的一个类,而MessageQueue是一个消息队列。那么是不是还差一个把消息放入MessageQueue中和把消息拿出来交给Handler处理的一个类呢。所以引入了一个Looper类:

Looper的主要功能:
  • Looper负责管理MessageQueue,会不断从MessageQueue中取出消息,并将消息分给对应的Handler处理。
获得一个Looper对象

上面提到每个线程最多只需要一个MessageQueue,所以一个线程中最多只能有一个Looper对象。看一下Looper构造器源码:

private Looper(){
    mQueue = new MessageQueue();
    mRun = true;
    mThread = mThread.currentThread();
}

可以看到构造器是使用private修饰的,所以程序员不能通过new来创建一个Looper对象。所以Looper类提供了一个prepare()方法来创建一个Looper对象。prepare()方法的源码:

private static final void prepare(){
    if(sThreadLocal.get() != null)
        throw new RuntimeException("Only one Looper may be created per thread");
    sThreadLocal.set(new Looper());
}

从上面的源码可以看出,prepare()对象保证了每个线程最多只有一个Looper对象。

通过Looper对象分发消息给Handler

当获得一个Looper对象之后,我们现在应该做的就是通过Looper对象,向MessageQueue中取出消息然后分发给Handler。Looper提供了静态的loop()方法。loop()方法使用一个死循环不断取出MessageQueue中的消息,并将取出的消息分给该消息对应的Handle进行处理。

总结

Looper、MessageQueue、Handler各自的作用:
  • Looper : 每个线程只有一个Looper,它负责管理MessageQueue,会不断从MessageQueue中取出消息,并将消息分给对应的Handler处理
  • MessageQueue : 由Looper负责管理。
  • Handler : 他能把消息发送给Looper管理的MessageQueue,并负责处理Looper分给它的消息。
新线程中使用Handler的步骤
  1. 调用Looper的perpare()方法为当前创建Looper对象,创建Looper对象时,他的构造器会创建与之配套的MessageQueue。
  2. 有了Looper之后,创建Handler子类的实例,重写handleMessage()方法,该方法负责处理来自其他线程的消息。
  3. 调用Looper的loop()方法启动Looper。
Handler 消息传递机制Android 开发中用于实现线程间通信,特别是在子线程执行耗时操作时与主线程通信以刷新 UI [^2]。以下是该机制中关键组件及工作原理的具体介绍: - **Message**:用于封装需要传递的消息,可携带数据,通常使用 `obtain` 方法创建。其内容一般是子线程对 UI 的操作 [^3]。 - **MessageQueue**:虽名为消息队列,但其内部通过单链表数据结构维护消息列表,便于插入和删除操作。主要功能是向消息池投递消息(`MessageQueue.enqueueMessage`)和取走消息池的消息(`MessageQueue.next`) [^3]。 - **Handler**:作为消息辅助,主要负责向消息发送各种消息事件(`Handler.sendMessage`),并处理相应的消息事件(`Handler.handleMessage`)。创建 Handler 对象时,系统会自动绑定 Looper 和对应的 MessageQueue [^3][^4]。 - **Looper**:持续循环执行(`Looper.loop`),从 MessageQueue 中读取消息,并按照分发机制消息分发给目标处理者 [^3]。 Handler 异步处理流程为:当创建 Handler 对象后,系统自动绑定 Looper 和 MessageQueue。之后,可使用 Handler 对象发送消息到 MessageQueue。Looper 不断循环,从 MessageQueue 中取出消息,并将其分发给对应的 Handler 进行处理 [^3][^4]。 此外,Android 消息机制引入了消息池。Handler 创建消息时,会先查询消息池中是否有可用消息,若有则直接获取,若无则重新初始化一个消息实例。使用消息池可提高消息对象的复用率,减少系统垃圾回收的次数 [^5]。 ### 示例代码 以下是一个简单的示例,展示了如何在新线程中计算质数,并使用 Handler 将结果发送到主线程显示: ```java import android.os.Handler; import android.os.Message; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import java.util.ArrayList; import java.util.List; public class PrimeNumberActivity extends AppCompatActivity { private TextView resultTextView; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_prime_number); resultTextView = findViewById(R.id.resultTextView); handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (msg.what == 1) { List<Integer> primes = (List<Integer>) msg.obj; StringBuilder result = new StringBuilder(); for (int prime : primes) { result.append(prime).append(" "); } resultTextView.setText("Prime numbers: " + result.toString()); } return true; } }); // 启动新线程计算质数 new Thread(new PrimeNumberCalculator(100)).start(); } private class PrimeNumberCalculator implements Runnable { private int limit; public PrimeNumberCalculator(int limit) { this.limit = limit; } @Override public void run() { List<Integer> primes = new ArrayList<>(); for (int i = 2; i <= limit; i++) { boolean isPrime = true; for (int j = 2; j < i; j++) { if (i % j == 0) { isPrime = false; break; } } if (isPrime) { primes.add(i); } } // 发送消息到主线程 Message message = Message.obtain(); message.what = 1; message.obj = primes; handler.sendMessage(message); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值