Android——Handler详解

1. 简介

Handler是一套 Android 消息传递机制,主要用于线程间通信。

用最简单的话描述: handler其实就是主线程在起了一个子线程,子线程运行并生成Message,Looper获取message并传递给Handler,Handler逐个获取子线程中的Message.

Binder/Socket用于进程间通信,而Handler消息机制用于同进程的线程间通信

可以说只要有异步线程与主线程通信的地方就一定会有 Handler。

在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现 工作线程对UI的更新处理,最终实现异步消息的处理
在这里插入图片描述
使用Handler消息传递机制主要是为了多个线程并发更新UI的同时,保证线程安全
在这里插入图片描述

2. 相关概念解释

Handler、Message、Message Queue、Looper

  • Message :代表一个行为what或者一串动作Runnable, 每一个消息在加入消息队列时,都有明确的目标Handler

  • ThreadLocal: 线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。ThreadLocal的作用是提供线程内的局部变量TLS,这种变量在线程的生命周期内起作用,每一个线程有他自己所属的值(线程隔离)

  • MessageQueue (C层与Java层都有实现) :以队列的形式对外提供插入和删除的工作, 其内部结构是以双向链表的形式存储消息的

  • Looper (C层与Java层都有实现) :Looper是循环的意思,它负责从消息队列中循环的取出消息然后把消息交给Handler处理

  • Handler :消息的真正处理者, 具备获取消息、发送消息、处理消息、移除消息等功能

在这里插入图片描述

Android消息机制:
在这里插入图片描述

  • 以Handler的sendMessage方法为例,当发送一个消息后,会将此消息加入消息队列MessageQueue中。
  • Looper负责去遍历消息队列并且将队列中的消息分发给对应的Handler进行处理。
  • 在Handler的handleMessage方法中处理该消息,这就完成了一个消息的发送和处理过程。

Handler示意图:
在这里插入图片描述
消息机制的模型:

  • Message:需要传递的消息,可以传递数据;
  • MessageQueue:消息队列,但是它的内部实现并不是用的队列,实际上是通过一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);
  • Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);
  • Looper:不断循环执行(Looper.loop),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。

消息机制的架构

  • 在子线程执行完耗时操作,当Handler发送消息时,将会调用 MessageQueue.enqueueMessage ,向消息队列中添加消息。
  • 当通过 Looper.loop 开启循环后,会不断地从线程池中读取消息,即调用 MessageQueue.next
  • 然后调用目标Handler(即发送该消息的Handler)的 dispatchMessage 方法传递消息,然后返回到Handler所在线程,目标Handler收到消息,调用 handleMessage 方法,接收消息,处理消息。

3. Handler 的基本使用

3.1 创建 Handler

Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。

这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。

解决方案:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息。

public class HandlerActivity extends AppCompatActivity {
   

    private Button bt_handler_send;

    private static class MyHandler extends Handler {
   

        //弱引用持有HandlerActivity , GC 回收时会被回收掉
        private WeakReference<HandlerActivity> weakReference;

        public MyHandler(HandlerActivity activity) {
   
            this.weakReference = new WeakReference(activity);
        }

        @Override
        public void handleMessage(Message msg) {
   
            HandlerActivity activity = weakReference.get();
            super.handleMessage(msg);
            if (null != activity) {
   
                //执行业务逻辑
                Toast.makeText(activity,"handleMessage",Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.HandlerActivity);

        //创建 Handler
        final MyHandler handler = new MyHandler(this);

        bt_handler_send = findViewById(R.id.bt_handler_send);
        bt_handler_send.setOnClickListener(new View.OnClickListener() {
   
            @Override
            public void onClick(View v) {
   
                new Thread(new Runnable() {
   
                    @Override
                    public void run() {
   
                        //使用 handler 发送空消息
                        handler.sendEmptyMessage(0);

                    }
                }).start();
            }
        });
    }
    
    @Override
    protected void onDestroy() {
   
        //移除所有回调及消息
        myHandler.removeCallbacksAndMessages(null);
        super.onDestroy();
    }
}

3.2 Message 获取

获取 Message 大概有如下几种方式:

Message message = myHandler.obtainMessage(); 		   //通过 Handler 实例获取
Message message1 = Message.obtain();   			      //通过 Message 获取
Message message2 = new Message();      				 //直接创建新的 Message 实例

通过查看源码可知,Handler 的 obtainMessage() 方法也是调用了 Message 的 obtain() 方法

public final Message obtainMessage()
{
   
    return Message.obtain(this);
}

通过查看 Message 的 obtain 方法

public static Message obtain(Handler h) {
   
        //调用下面的方法获取 Message
        Message m = obtain();
        //将当前 Handler 指定给 message 的 target ,用来区分是哪个 Handler 的消息
        m.target = h;

        return m;
    }
    
//从消息池中拿取 Message,如果有则返回,否则创建新的 Message
public static Message obtain() {
   
        synchronized (sPoolSync) {
   
            if (sPool != null) {
   
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

为了节省开销,我们在使用的时候尽量复用 Message,使用前两种方式进行创建。

3.3 Handler 发送消息

Handler 提供了一些列的方法让我们来发送消息,如 send()系列 post()系列,post方法需要传入一个Runnalbe对象 ,我们来看看post方法源码

    public final boolean post(Runnable r)
    {
   
       return  sendMessageDelayed(getPostMessage(r), 0
### AndroidHandler 机制的工作原理 #### 主要组件介绍 Handler 机制主要由四个核心部分组成: - **Message 和 MessageQueue** `Message` 是在线程间传递的数据对象,可以携带少量数据。`MessageQueue` 则是一个消息队列,用来保存这些待处理的消息。当有新的消息到来时会被加入到此队列中等待被处理[^1]。 - **Looper** Looper 对象负责管理特定线程中的 `MessageQueue` 。每个线程最多只有一个 Looper 实例,并且它会持续循环读取消息并分发给相应的处理器 (即 Handler)。 - **Handler** Handler 类主要用于两个方面:一是在新启动的子线程里发送消息至主线程;二是接收来自其他地方发出的信息,在当前上下文中对其进行相应操作。通过关联指定的 Looper 来实现跨线程通信功能[^2]。 #### 创建与初始化过程 为了确保安全有效地使用 Handler 进行异步任务调度,通常建议采用如下方式来构建相关实例: ```java // 定义一个新的继承自 Handler 的类 class MyHandler extends Handler { public MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // 处理接收到的消息逻辑... } } // 启动带有 Looper 的特殊线程 HandlerThread thread = new HandlerThread("MyHandlerThread"); thread.start(); // 获取该线程上的 Looper 并创建对应的 Handler MyHandler myHandler = new MyHandler(thread.getLooper()); ``` 这段代码展示了如何在一个独立于应用程序主 UI 线程之外的地方设置好能够正常工作的 Handler 及其依赖环境[^3]。 #### 消息处理流程 一旦设置了上述结构之后,就可以利用 sendEmptyMessage() 或 sendMessage() 方法向目标 Handler 发送请求了。而实际的消息派发则发生在 Looper.loop() 函数内部的一个无限循环内——每当检测到队首存在未决项便会立即取出交给合适的回调函数去完成具体业务需求[^4]。 ```java public final boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); } ``` 以上就是关于 AndroidHandler 工作模式较为全面的技术解析。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yawn__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值