详解Android的消息机制

本文详细剖析了Android的Handler消息机制,包括Handler的发送消息、MessageQueue的工作原理、Looper的运行流程以及Handler如何处理消息。文章通过源码分析,解释了Message、Handler、MessageQueue和Looper之间的交互,同时探讨了ThreadLocal的作用。文中还提到了主线程中Looper的创建以及为何一个线程只有一个Looper和MessageQueue。
摘要由CSDN通过智能技术生成


前言

Handler是Android消息机制的上层接口,所以Android的消息机制主要指的就是Handler的运行机制,其主要应用于UI线程(主线程)和子线程之间的交互。众所周知,一般情况下,出于安全的考虑,所有与UI控件的操作都要放在主线程,而一些耗时的I/O操作应当放在子线程中。当在子线程中完成耗时操作并要对UI控件进行操作时,此时就要用Handler来控制了。

在这我们先来简述一下Handler的运行过程:

在Handler创建完毕后,这个时候其内部的Looper以及MessageQueue就可以和Handler一起协同工作了,然后通过Handler的post方法将个Runnable 投递到Handler内部的Looper中去处理,也可以通过Handler的send方法发送个消息,这个消息同样会在Looper中去处理。其实post方法最终也是通过send方法来完成的,接下来主要来看一下send方法的工作过程。当Handler的send方法被调用时,它会调用MessageQueue的enqueueMessage方法将这个消息放入消息队列中,然后Looper发现有新消息到来时,就会处理这个消息,最终消息中的Runnable或者Handler 的handleMessage 方法就会被调用。注意Looper是运行在创建Handler所在的线程中的,这样-来Handler中的业务逻辑就被切换到创建Handler所在的线程中去执行了。

本文主要以解析Handler源码为主,包含Handler运行机制MessageQueue的工作原理Looper的工作原理ThreadLocal的工作原理

首先我们先简介一下关于Handler机制中会出现的一些概念:

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

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

MessageQueue:消息队列,以队列(实质还是链表)的形式对外提供插入和删除的操作,其内部结构是以链表的形式存储消息的。

Looper:Looper是循环的意思,它负责从消息队列(MessageQueue)中循环的取出消息然后把消息交给目标(Handler)处理。

线程:线程,CPU调度资源的基本单位。Android中的消息机制也是基于线程来完成的。

ThreadLocal:ThreadLocal的作用是提供线程内的局部变量(TLS),这种变量在线程的生命周期内起作用,每一个线程有他自己所属的值(线程隔离)。


一、Handler发送消息机制

1.Handler的简单使用

我们先通过一个简单的代码展示一下Handler的用法:

public class MainActivity extends AppCompatActivity {
   
	private Handler handler = new Handler(){
   
	    @Override
	    public void handleMessage(Message msg) {
   
            switch(msg.what){
   
            	case 1:{
   
            		Toast.makeText(MainActivity.this,"UI操作",Toast.LENGTH_SHORT).show();
            	}
            }
	    }
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState){
   
	       super.onCreate(savedInstanceState);
	       setContentView(R.layout.activity_main);
	       new Thread(new Runnable() {
   
	           @Override
	           public void run() {
   
	               /*
	               *网络请求操作或者耗时的I/O操作
	               *
	               */
	            Message message = new Message();
                message.what = 1;
                handler.sendMessage(message);
	           }
	       }).start();
	   }
}

通过这段代码可以看到,我们在子线程中通过handler发送一个消息 Message,然后再由此handler处理接收到的消息,这样我们就可以实现在子线程里完成耗时的I/O操作,完成后我们再切换到主线程完成对UI的操作。

那Handler内部是怎么发送消息,又是怎么处理消息的呢?

2.Handler如何发送消息?

由于Handler中所有post方法最终都会调用send方法,所以这里不予讲述

    public final boolean sendMessage(@NonNull Message msg) {
   
        return sendMessageDelayed(msg, 0);
    }

    public final boolean sendEmptyMessage(int what) {
   
        return sendEmptyMessageDelayed(what, 0);
    }

    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
   
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

通过Handler的源码我们可以看出,sendMessage()和sendEmptyMessage(),最终都会调用sendMessageDelayed()方法。不同之处在于,sendMessage()方法接受的是一个Message对象,然后将这个对象传给sendMessageDelayed(),而sendEmptyMessage()需要的是一个名为what的int值,然后通过Message.obtain()方法得到一个Mesage对象,再将what值赋给他,最后传给sendMessageDelayed()。

那么我们需要思考一下what值是干什么的?还有就是new出来的Message对象和调用Message.obtain()方法得到的对象这两个有什么区别呢?

首先我们看一下Message类下what的简介:

    /**
     * User-defined message code so that the recipient can identify
     * what this message is about. Each {@link Handler} has its own name-space
     * for message codes, so you do not need to worry about yours conflicting
     * with other handlers.
     */
    public int what;

翻译:用户定义的消息代码,以便收件者可以确定这条消息是关于什么。每个{@link Handler}都有自己的消息代码名称空间,因此您不必担心与其他Handlers发生冲突。

可见,what值就是消息的一个代号,由于不同的Handler都有自己的命名空间,所以我们不必担心会引起冲突。

那我们再看一下obtain():

    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    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实例。允许我们在许多情况下避免分配新对象。

看代码,我们大概能看出Android为我们定义好了一个全局的Message池,这个池是一个链表型数据结构,通过obtain()方法可以从链表头取出一个Message对象并返回。

上面的两个疑问解决了,我们继续往下看,由于sendMessage()和sendEmptyMessage()最终都会调用sendMessageDelayed()方法,那我们一起看一下sendMessageDela

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值