Handler机制

深入理解Handler机制

Handler机制中涉及到几个比较重要的类:Handler、Looper、Message、和MessageQueue。UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。Hander持有对消息队列MessageQueue和消息循环器Looper的引用,子线程可以通过Handler将消息Message发送到消息队列MessageQueue中。UI主线程通过Looper循环查询消息队列,当发现有消息存在时会将消息Message从消息队列中取出,将消息Message分发给相应的Handler进行处理。
对于Handler机制的源码分析分析文章很多,在此对源码就不多说了。下面通过自定义Hander 、Looper、 MessageQueue和 Message,加深大家对Handler机制的理解。
1.Handler类:类里有两个重要的成员变量MessageQueue mQueue和Looper mLooper,也就是,Handler被实例化的时候,持有MessageQueue和Looper 的引用,Handler中两个很重要的函数:sendMessage(Message msg)和handleMessage(Message msg),子线程发送消息时,调用前者,Looper从消息队列MessageQueue取出Message时,会调用handleMessage(Message msg)处理消息,所以我们在实例化Handler的时候,重写handleMessage(Message msg)函数,该函数就会被回调。

package mhandler;

public class Handler {
    public MessageQueue mQueue;//消息队列
    private Looper mLooper;



    public Handler() {
        mLooper = Looper.myLooper();//获取当前线程的looper对象
        this.mQueue = mLooper.mQueue;
    }



    /**
     * 发送消息,把message对象加入消息队列
     * @param msg
     */
    public void sendMessage(Message msg){
        msg.handler = this;
        //Message消息压入消息队列
        mQueue.enqueueMessage(msg);

    }

    public void dispatchMessage(Message msg){
        handleMessage(msg);

    }

    public void handleMessage(Message msg){


    }



}

2.Looper:消息轮询器。通过ThreadLocal存取Looper,每个线程只允许创建一个Looper,在UI主线程中,已经调用了prepare()函数实例化了一个Looper,所以不需要程序员去实例化looper,在最后也调用了loop()函数,开启轮询。若在子线程中实例化Handler对象,则需要先调用prepare()最后调用loop()函数。Looper的作用是不断地循环查询消息队列,当发现有消息存在时,会将消息Message从消息队列中取出,将消息Message分发给相应的Handler进行处理。

package mhandler;

public final class Looper {
    //looper对象保存在ThreadLocal,保证了线程数据的隔离
    static final ThreadLocal<Looper> mThreadLocal = new ThreadLocal<Looper>();
    MessageQueue mQueue;

    private Looper(){

        mQueue = new MessageQueue();
    }

    /**
     * 初始化looper,将其加入mThreadLocal
     */
    public static void prepare(){
        if (mThreadLocal.get() != null) {
            throw new RuntimeException("一个线程只能拥有一个looper");

        }
        mThreadLocal.set(new Looper());

    }

    /**
     * 获取looper对象
     * @return
     */
    public static Looper myLooper(){
        return mThreadLocal.get();

    }

    /**
     * 轮询消息队列
     */
    public static void loop(){
        Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("looper空,请先调用prepare()实例化looper对象");

        }
        MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next();
            if (msg == null) {
                continue;

            }
            msg.handler.dispatchMessage(msg);

        }

    }

}

3.Message:消息类,持有一个Handler 的引用

package mhandler;

public class Message {
    public int what;
    public Object obj;
    Handler handler;

}

4.MessageQueue:消息队列,以链表的数据结构存取Message,源码中Message对象还有时间when属性,默认情况下,Message的when为存储时的时间,若调用了sendMessageDelayed(Message msg, long delayMillis)函数,则when = 当前时间+delay的时间,MessageQueue会按照时间顺序把Message加入队列。

package mhandler;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MessageQueue {
    Message[] items;//存放消息的数组
    private int putIndex;
    private int takeIndex;
    private int count;

    //互斥锁
    private Lock lock;
    private Condition notEmpty;
    private Condition notfull;

    public MessageQueue() {

        this.items = new Message[50];
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition(); 
        this.notfull = lock.newCondition(); 

    }

    /**
     * 子线程加入消息队列
     * @param msg
     */
    public void enqueueMessage(Message msg){
        try {
            lock.lock();//枷锁
            //消息队列已满,子线程阻塞,停止消息加入队列
            while(count == items.length){
                try {
                    notfull.await();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

            items[putIndex] = msg;
            //如果putIndex等于数组长度,则归零
            putIndex = (++putIndex == items.length) ? 0 : putIndex;
            count ++;
            //通知主线程停止阻塞
            notEmpty.signalAll();


        } finally {
            lock.unlock();

        }



    }

    /**
     * 主线程消息出队
     * @return
     */
    public Message next(){
        try {
            lock.lock();//枷锁
            //消息队列为空,主线程阻塞
            while(count == 0){
                try {
                    notEmpty.await();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

            Message msg = items[takeIndex];
            items[takeIndex] = null;
            takeIndex = (++takeIndex == items.length) ? 0 : takeIndex;
            count --;
            //通知子线程停止阻塞
            notfull.signalAll();
            return msg;

        } finally {
            lock.unlock();

        }


    }

}

完整demo下载地址:http://download.youkuaiyun.com/detail/chen20142015/9800242

### 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机制解决实际开发中的并发问题和提高应用性能。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值