解析Handler异步消息处理!

本文详细解析了Android中Handler的异步消息处理机制,包括Message、Handler、MessageQueue和Looper的角色与作用。强调了主线程不会因Looper.loop()的死循环卡死的原因,解释了HandlerThread的使用场景和优势,以及线程间如何通过Handler进行通信。

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

Handler中异步消息处理一般由四个部分组成,Message、Handler、MessageQueue和Looper。

1、Message :是在线程之间传递消息,它可以携带信息,用于不同线程之间交互数据。它里面字段有
waht、arg1、arg2(int类型)、object型数据。

2、Handler: 它主要用于发送消息和处理消息,发送消息一般是使用Handler的sendMessage()方法,
发出消息之后,辗转处理后,最终会传递到handlerMessage()中

3、MessageQueue:消息队列,它主要存放handler发送的消息。这部分消息会一直存放在队列中,等待
被处理。每个线程中只有一个MessageQueue队列。

4、Looper:是MessageQueue队列的管家,调用loop()方法后,就会进入到一个无线循环当中,然后每当
发现队列中有消息,就会取出,并传递到Handler的handlerMessage方法中()。

了解了上面的几个的基本概念之后,我们再把异步消息处理的流程梳理一遍,首先需要在主线程中创建一个Handler对象,并重写handlerMessage()方法。然后当子线程中更新UI的时候,我们先创建一个Message对象,并通过Handler发送出去。之后这条消息会被添加到MessageQueue队列中等待被处理,而Looper一直尝试从队列中取消息,最后分发到handlerMessage()方法中。由于Handler是在主线程创建的,所以handlerMessage()方法会在主线程中运行,于是我们就可以更新UI了。
以下是流程图:

这里写图片描述

总结:以上是Handler的运行机制,也是如何在子线程中辗转到主线程的流程!!

能不能在子线程中,创建Handler
 new Thread() {
                    @Override
                    public void run() {
                        // 在子线程中发送异步消息
                        mHandler.sendEmptyMessage(101);
                    }
                }.start();

在这里插入图片描述
标准写法:

  // 初始化该线程Looper,MessageQueue,执行且只能执行一次
                Looper.prepare();
                // 初始化Handler对象,内部关联Looper对象
                Handler mHandler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                    }
                };
                // 启动消息队列出栈死循环
                Looper.loop();

要求我们必须创建一个Looper对象,所以在子线程创建Handler必须创建一个Looper。 只能创建一个Looper,创建两个也会报错。

总结:

  • 一个线程只能存在一个Looper,只存在一个MessageQueue对象,可以存在N个Handler
  • MessageQueue 是通过时间排序的
  • android中两个子线程相互交互同样可以通过Handler的异步消息机制实现,可以在线程a中定义Handler对象,而在线程b中获取handler的引用并调用sendMessage方法
为什么主线程不会因为Looper.loop()里的死循环卡死
public static void main(String[] args) {
        ....
 
        //创建Looper和MessageQueue对象,用于处理主线程的消息
        Looper.prepareMainLooper();
 
        //创建ActivityThread对象
        ActivityThread thread = new ActivityThread(); 
 
        //建立Binder通道 (创建新线程)
        thread.attach(false);
 
        Looper.loop(); //消息循环运行
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

1、:进入死循环前创建了新binder线程
2、.通过管道机制,主线程大多时候处于休眠状态,不会消耗大量cpu资源导致程序卡死

HandlerThread

正常用法:

/**
 * 测试HandlerThread的基本使用
 */
HandlerThread mHandlerThread = new HandlerThread("myHandlerThreand");
        mHandlerThread.start();

        // 创建的Handler将会在mHandlerThread线程中执行
        final Handler mHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                Log.i("tag", "接收到消息:" + msg.obj.toString());
            }
        };

                Message msg = new Message();
                msg.obj = "11111";
                mHandler.sendMessage(msg);   
          }

HandlerThread继承Thread,本质就是一个线程,调用start()方法之后,后执行run方法:

@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
  • 内部调用了Looper.prepate()方法和Loop.loop()方法,在android体系中一个线程其实是对应着一个Looper对象、一个MessageQueue对象,以及N个Handler对象。
  • 所以通过run方法,我们可以知道在我们创建的HandlerThread线程中我们创建了该线程的Looper与MessageQueue;

不需要的时候需要手动释放:

  protected void onDestroy() {
           super.onDestroy();
           mHandlerThread.quit();
       }
总结:
  • HandlerThread本质上是一个Thread对象,只不过其内部帮我们创建了该线程的Looper和MessageQueue;
  • 通过HandlerThread我们不但可以实现UI线程与子线程的通信同样也可以实现子线程与子线程之间的通信;
  • HandlerThread在不需要使用的时候需要手动的回收掉;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值